Merge mozilla-inbound to mozilla-central. a=merge
authorDorel Luca <dluca@mozilla.com>
Fri, 27 Jul 2018 13:19:26 +0300
changeset 483797 87bcafe428a4
parent 483754 e56f7601927e (current diff)
parent 483796 ad1674e9152d (diff)
child 483812 20335ff1bf9e
child 483835 53ea40188efa
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone63.0a1
first release with
nightly linux32
87bcafe428a4 / 63.0a1 / 20180727103347 / files
nightly linux64
87bcafe428a4 / 63.0a1 / 20180727103347 / files
nightly mac
87bcafe428a4 / 63.0a1 / 20180727103347 / files
nightly win32
87bcafe428a4 / 63.0a1 / 20180727103347 / files
nightly win64
87bcafe428a4 / 63.0a1 / 20180727103347 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge mozilla-inbound to mozilla-central. a=merge
.eslintignore
CLOBBER
browser/base/content/test/performance/browser_preferences_usage.js
browser/base/content/test/tabs/browser_isLocalAboutURI.js
browser/components/newtab/lib/ActivityStreamMessageChannel.jsm
browser/components/newtab/moz.build
browser/components/newtab/tests/browser/.eslintrc.js
browser/components/newtab/tests/browser/browser.ini
browser/components/newtab/tests/browser/browser_activity_stream_strings.js
browser/components/newtab/tests/browser/browser_enabled_newtabpage.js
browser/components/newtab/tests/browser/browser_newtab_overrides.js
browser/components/newtab/tests/browser/browser_packaged_as_locales.js
browser/components/newtab/tests/xpcshell/.eslintrc.js
browser/components/newtab/tests/xpcshell/test_AboutNewTabService.js
browser/components/newtab/tests/xpcshell/xpcshell.ini
browser/extensions/activity-stream/.eslintignore
browser/extensions/activity-stream/.eslintrc.js
browser/extensions/activity-stream/.mcignore
browser/extensions/activity-stream/.nvmrc
browser/extensions/activity-stream/.sass-lint.yml
browser/extensions/activity-stream/.taskcluster.yml
browser/extensions/activity-stream/.travis.yml
browser/extensions/activity-stream/CODEOWNERS
browser/extensions/activity-stream/LICENSE
browser/extensions/activity-stream/README.md
browser/extensions/activity-stream/bin/download-firefox-artifact
browser/extensions/activity-stream/bin/download-firefox-travis.sh
browser/extensions/activity-stream/bin/locales.js
browser/extensions/activity-stream/bin/prepare-mochitests-dev
browser/extensions/activity-stream/bin/process-system-addon-for-package.js
browser/extensions/activity-stream/bin/render-activity-stream-html.js
browser/extensions/activity-stream/bin/strings-import.js
browser/extensions/activity-stream/bin/test-merges.js
browser/extensions/activity-stream/bin/update-version.js
browser/extensions/activity-stream/bootstrap.js
browser/extensions/activity-stream/common/Actions.jsm
browser/extensions/activity-stream/common/Dedupe.jsm
browser/extensions/activity-stream/common/PerfService.jsm
browser/extensions/activity-stream/common/PrerenderData.jsm
browser/extensions/activity-stream/common/Reducers.jsm
browser/extensions/activity-stream/content-src/.eslintrc.js
browser/extensions/activity-stream/content-src/activity-stream-prerender.jsx
browser/extensions/activity-stream/content-src/activity-stream.jsx
browser/extensions/activity-stream/content-src/asrouter/asrouter-content.jsx
browser/extensions/activity-stream/content-src/asrouter/components/Button/Button.jsx
browser/extensions/activity-stream/content-src/asrouter/components/Button/_Button.scss
browser/extensions/activity-stream/content-src/asrouter/components/ImpressionsWrapper/ImpressionsWrapper.jsx
browser/extensions/activity-stream/content-src/asrouter/components/ModalOverlay/ModalOverlay.jsx
browser/extensions/activity-stream/content-src/asrouter/components/ModalOverlay/_ModalOverlay.scss
browser/extensions/activity-stream/content-src/asrouter/components/SnippetBase/SnippetBase.jsx
browser/extensions/activity-stream/content-src/asrouter/components/SnippetBase/_SnippetBase.scss
browser/extensions/activity-stream/content-src/asrouter/schemas/message-format.md
browser/extensions/activity-stream/content-src/asrouter/schemas/provider-response.schema.json
browser/extensions/activity-stream/content-src/asrouter/template-utils.js
browser/extensions/activity-stream/content-src/asrouter/templates/OnboardingMessage/OnboardingMessage.jsx
browser/extensions/activity-stream/content-src/asrouter/templates/OnboardingMessage/_OnboardingMessage.scss
browser/extensions/activity-stream/content-src/asrouter/templates/SimpleSnippet/SimpleSnippet.jsx
browser/extensions/activity-stream/content-src/asrouter/templates/SimpleSnippet/SimpleSnippet.schema.json
browser/extensions/activity-stream/content-src/asrouter/templates/SimpleSnippet/_SimpleSnippet.scss
browser/extensions/activity-stream/content-src/components/ASRouterAdmin/ASRouterAdmin.jsx
browser/extensions/activity-stream/content-src/components/ASRouterAdmin/ASRouterAdmin.scss
browser/extensions/activity-stream/content-src/components/Base/Base.jsx
browser/extensions/activity-stream/content-src/components/Base/_Base.scss
browser/extensions/activity-stream/content-src/components/Card/Card.jsx
browser/extensions/activity-stream/content-src/components/Card/_Card.scss
browser/extensions/activity-stream/content-src/components/Card/types.js
browser/extensions/activity-stream/content-src/components/CollapsibleSection/CollapsibleSection.jsx
browser/extensions/activity-stream/content-src/components/CollapsibleSection/_CollapsibleSection.scss
browser/extensions/activity-stream/content-src/components/ComponentPerfTimer/ComponentPerfTimer.jsx
browser/extensions/activity-stream/content-src/components/ConfirmDialog/ConfirmDialog.jsx
browser/extensions/activity-stream/content-src/components/ConfirmDialog/_ConfirmDialog.scss
browser/extensions/activity-stream/content-src/components/ContextMenu/ContextMenu.jsx
browser/extensions/activity-stream/content-src/components/ContextMenu/_ContextMenu.scss
browser/extensions/activity-stream/content-src/components/ErrorBoundary/ErrorBoundary.jsx
browser/extensions/activity-stream/content-src/components/ErrorBoundary/_ErrorBoundary.scss
browser/extensions/activity-stream/content-src/components/LinkMenu/LinkMenu.jsx
browser/extensions/activity-stream/content-src/components/ManualMigration/ManualMigration.jsx
browser/extensions/activity-stream/content-src/components/ManualMigration/_ManualMigration.scss
browser/extensions/activity-stream/content-src/components/Search/Search.jsx
browser/extensions/activity-stream/content-src/components/Search/_Search.scss
browser/extensions/activity-stream/content-src/components/SectionMenu/SectionMenu.jsx
browser/extensions/activity-stream/content-src/components/Sections/Sections.jsx
browser/extensions/activity-stream/content-src/components/Sections/_Sections.scss
browser/extensions/activity-stream/content-src/components/StartupOverlay/StartupOverlay.jsx
browser/extensions/activity-stream/content-src/components/StartupOverlay/_StartupOverlay.scss
browser/extensions/activity-stream/content-src/components/TopSites/TopSite.jsx
browser/extensions/activity-stream/content-src/components/TopSites/TopSiteForm.jsx
browser/extensions/activity-stream/content-src/components/TopSites/TopSiteFormInput.jsx
browser/extensions/activity-stream/content-src/components/TopSites/TopSites.jsx
browser/extensions/activity-stream/content-src/components/TopSites/TopSitesConstants.js
browser/extensions/activity-stream/content-src/components/TopSites/_TopSites.scss
browser/extensions/activity-stream/content-src/components/Topics/Topics.jsx
browser/extensions/activity-stream/content-src/components/Topics/_Topics.scss
browser/extensions/activity-stream/content-src/lib/constants.js
browser/extensions/activity-stream/content-src/lib/detect-user-session-start.js
browser/extensions/activity-stream/content-src/lib/init-store.js
browser/extensions/activity-stream/content-src/lib/link-menu-options.js
browser/extensions/activity-stream/content-src/lib/screenshot-utils.js
browser/extensions/activity-stream/content-src/lib/section-menu-options.js
browser/extensions/activity-stream/content-src/lib/snippets.js
browser/extensions/activity-stream/content-src/styles/_activity-stream.scss
browser/extensions/activity-stream/content-src/styles/_icons.scss
browser/extensions/activity-stream/content-src/styles/_normalize.scss
browser/extensions/activity-stream/content-src/styles/_theme.scss
browser/extensions/activity-stream/content-src/styles/_variables.scss
browser/extensions/activity-stream/content-src/styles/activity-stream-linux.scss
browser/extensions/activity-stream/content-src/styles/activity-stream-mac.scss
browser/extensions/activity-stream/content-src/styles/activity-stream-windows.scss
browser/extensions/activity-stream/contributing.md
browser/extensions/activity-stream/css/activity-stream-linux.css
browser/extensions/activity-stream/css/activity-stream-linux.css.map
browser/extensions/activity-stream/css/activity-stream-mac.css
browser/extensions/activity-stream/css/activity-stream-mac.css.map
browser/extensions/activity-stream/css/activity-stream-windows.css
browser/extensions/activity-stream/css/activity-stream-windows.css.map
browser/extensions/activity-stream/data/content/activity-stream.bundle.js
browser/extensions/activity-stream/data/content/activity-stream.bundle.js.map
browser/extensions/activity-stream/data/content/assets/fox-tail.png
browser/extensions/activity-stream/data/content/assets/glyph-add-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-arrowhead-down-12.svg
browser/extensions/activity-stream/data/content/assets/glyph-arrowhead-down-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-cancel-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-delete-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-dismiss-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-edit-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-highlights-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-import-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-info-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-maximize-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-minimize-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-modal-delete-32.svg
browser/extensions/activity-stream/data/content/assets/glyph-newWindow-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-open-file-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-pin-12.svg
browser/extensions/activity-stream/data/content/assets/glyph-pin-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-pocket-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-topsites-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-trending-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-unpin-16.svg
browser/extensions/activity-stream/data/content/assets/glyph-webextension-16.svg
browser/extensions/activity-stream/data/content/assets/illustration-addons@2x.png
browser/extensions/activity-stream/data/content/assets/illustration-gift@2x.png
browser/extensions/activity-stream/data/content/assets/illustration-privatebrowsing@2x.png
browser/extensions/activity-stream/data/content/assets/illustration-screenshots@2x.png
browser/extensions/activity-stream/data/content/assets/sync-devices.svg
browser/extensions/activity-stream/data/content/assets/topic-show-more-12.svg
browser/extensions/activity-stream/data/content/tippytop/images/aliexpress-com@2x.png
browser/extensions/activity-stream/data/content/tippytop/images/allegro-pl@2x.png
browser/extensions/activity-stream/data/content/tippytop/images/amazon@2x.png
browser/extensions/activity-stream/data/content/tippytop/images/avito-ru@2x.png
browser/extensions/activity-stream/data/content/tippytop/images/bbc-uk@2x.png
browser/extensions/activity-stream/data/content/tippytop/images/ebay@2x.png
browser/extensions/activity-stream/data/content/tippytop/images/facebook-com@2x.png
browser/extensions/activity-stream/data/content/tippytop/images/leboncoin-fr@2x.png
browser/extensions/activity-stream/data/content/tippytop/images/ok-ru@2x.png
browser/extensions/activity-stream/data/content/tippytop/images/olx-pl@2x.png
browser/extensions/activity-stream/data/content/tippytop/images/reddit-com@2x.png
browser/extensions/activity-stream/data/content/tippytop/images/twitter-com@2x.png
browser/extensions/activity-stream/data/content/tippytop/images/vk-com@2x.png
browser/extensions/activity-stream/data/content/tippytop/images/wikipedia-org@2x.png
browser/extensions/activity-stream/data/content/tippytop/images/wykop-pl@2x.png
browser/extensions/activity-stream/data/content/tippytop/images/youtube-com@2x.png
browser/extensions/activity-stream/data/content/tippytop/top_sites.json
browser/extensions/activity-stream/docs/ISSUE_TEMPLATE.md
browser/extensions/activity-stream/docs/v2-system-addon/1.GETTING_STARTED.md
browser/extensions/activity-stream/docs/v2-system-addon/data_dictionary.md
browser/extensions/activity-stream/docs/v2-system-addon/data_events.md
browser/extensions/activity-stream/docs/v2-system-addon/mochitests.md
browser/extensions/activity-stream/docs/v2-system-addon/preferences.md
browser/extensions/activity-stream/docs/v2-system-addon/sections.md
browser/extensions/activity-stream/docs/v2-system-addon/snippets.md
browser/extensions/activity-stream/docs/v2-system-addon/telemetry.md
browser/extensions/activity-stream/docs/v2-system-addon/test-merges.md
browser/extensions/activity-stream/docs/v2-system-addon/unit_testing_guide.md
browser/extensions/activity-stream/install.rdf.in
browser/extensions/activity-stream/jar.mn
browser/extensions/activity-stream/karma.mc.config.js
browser/extensions/activity-stream/lib/ASRouter.jsm
browser/extensions/activity-stream/lib/ASRouterFeed.jsm
browser/extensions/activity-stream/lib/ASRouterTargeting.jsm
browser/extensions/activity-stream/lib/AboutPreferences.jsm
browser/extensions/activity-stream/lib/ActivityStream.jsm
browser/extensions/activity-stream/lib/ActivityStreamMessageChannel.jsm
browser/extensions/activity-stream/lib/ActivityStreamPrefs.jsm
browser/extensions/activity-stream/lib/ActivityStreamStorage.jsm
browser/extensions/activity-stream/lib/DownloadsManager.jsm
browser/extensions/activity-stream/lib/FaviconFeed.jsm
browser/extensions/activity-stream/lib/FilterAdult.jsm
browser/extensions/activity-stream/lib/HighlightsFeed.jsm
browser/extensions/activity-stream/lib/LinksCache.jsm
browser/extensions/activity-stream/lib/ManualMigration.jsm
browser/extensions/activity-stream/lib/NewTabInit.jsm
browser/extensions/activity-stream/lib/OnboardingMessageProvider.jsm
browser/extensions/activity-stream/lib/PersistentCache.jsm
browser/extensions/activity-stream/lib/PlacesFeed.jsm
browser/extensions/activity-stream/lib/PrefsFeed.jsm
browser/extensions/activity-stream/lib/Screenshots.jsm
browser/extensions/activity-stream/lib/SectionsManager.jsm
browser/extensions/activity-stream/lib/ShortURL.jsm
browser/extensions/activity-stream/lib/SnippetsFeed.jsm
browser/extensions/activity-stream/lib/Store.jsm
browser/extensions/activity-stream/lib/SystemTickFeed.jsm
browser/extensions/activity-stream/lib/TelemetryFeed.jsm
browser/extensions/activity-stream/lib/TippyTopProvider.jsm
browser/extensions/activity-stream/lib/TopSitesFeed.jsm
browser/extensions/activity-stream/lib/TopStoriesFeed.jsm
browser/extensions/activity-stream/lib/UTEventReporting.jsm
browser/extensions/activity-stream/lib/UserDomainAffinityProvider.jsm
browser/extensions/activity-stream/loaders/inject-loader.js
browser/extensions/activity-stream/locales/ach/strings.properties
browser/extensions/activity-stream/locales/an/strings.properties
browser/extensions/activity-stream/locales/ar/strings.properties
browser/extensions/activity-stream/locales/ast/strings.properties
browser/extensions/activity-stream/locales/az/strings.properties
browser/extensions/activity-stream/locales/be/strings.properties
browser/extensions/activity-stream/locales/bg/strings.properties
browser/extensions/activity-stream/locales/bn-BD/strings.properties
browser/extensions/activity-stream/locales/bn-IN/strings.properties
browser/extensions/activity-stream/locales/br/strings.properties
browser/extensions/activity-stream/locales/bs/strings.properties
browser/extensions/activity-stream/locales/ca/strings.properties
browser/extensions/activity-stream/locales/cak/strings.properties
browser/extensions/activity-stream/locales/crh/strings.properties
browser/extensions/activity-stream/locales/cs/strings.properties
browser/extensions/activity-stream/locales/cy/strings.properties
browser/extensions/activity-stream/locales/da/strings.properties
browser/extensions/activity-stream/locales/de/strings.properties
browser/extensions/activity-stream/locales/dsb/strings.properties
browser/extensions/activity-stream/locales/el/strings.properties
browser/extensions/activity-stream/locales/en-CA/strings.properties
browser/extensions/activity-stream/locales/en-GB/strings.properties
browser/extensions/activity-stream/locales/en-US/strings.properties
browser/extensions/activity-stream/locales/eo/strings.properties
browser/extensions/activity-stream/locales/es-AR/strings.properties
browser/extensions/activity-stream/locales/es-CL/strings.properties
browser/extensions/activity-stream/locales/es-ES/strings.properties
browser/extensions/activity-stream/locales/es-MX/strings.properties
browser/extensions/activity-stream/locales/et/strings.properties
browser/extensions/activity-stream/locales/eu/strings.properties
browser/extensions/activity-stream/locales/fa/strings.properties
browser/extensions/activity-stream/locales/ff/strings.properties
browser/extensions/activity-stream/locales/fi/strings.properties
browser/extensions/activity-stream/locales/fr/strings.properties
browser/extensions/activity-stream/locales/fy-NL/strings.properties
browser/extensions/activity-stream/locales/ga-IE/strings.properties
browser/extensions/activity-stream/locales/gd/strings.properties
browser/extensions/activity-stream/locales/gl/strings.properties
browser/extensions/activity-stream/locales/gn/strings.properties
browser/extensions/activity-stream/locales/gu-IN/strings.properties
browser/extensions/activity-stream/locales/he/strings.properties
browser/extensions/activity-stream/locales/hi-IN/strings.properties
browser/extensions/activity-stream/locales/hr/strings.properties
browser/extensions/activity-stream/locales/hsb/strings.properties
browser/extensions/activity-stream/locales/hu/strings.properties
browser/extensions/activity-stream/locales/hy-AM/strings.properties
browser/extensions/activity-stream/locales/ia/strings.properties
browser/extensions/activity-stream/locales/id/strings.properties
browser/extensions/activity-stream/locales/it/strings.properties
browser/extensions/activity-stream/locales/ja-JP-mac/strings.properties
browser/extensions/activity-stream/locales/ja/strings.properties
browser/extensions/activity-stream/locales/ka/strings.properties
browser/extensions/activity-stream/locales/kab/strings.properties
browser/extensions/activity-stream/locales/kk/strings.properties
browser/extensions/activity-stream/locales/km/strings.properties
browser/extensions/activity-stream/locales/kn/strings.properties
browser/extensions/activity-stream/locales/ko/strings.properties
browser/extensions/activity-stream/locales/lij/strings.properties
browser/extensions/activity-stream/locales/lo/strings.properties
browser/extensions/activity-stream/locales/lt/strings.properties
browser/extensions/activity-stream/locales/ltg/strings.properties
browser/extensions/activity-stream/locales/lv/strings.properties
browser/extensions/activity-stream/locales/mai/strings.properties
browser/extensions/activity-stream/locales/mk/strings.properties
browser/extensions/activity-stream/locales/ml/strings.properties
browser/extensions/activity-stream/locales/mr/strings.properties
browser/extensions/activity-stream/locales/ms/strings.properties
browser/extensions/activity-stream/locales/my/strings.properties
browser/extensions/activity-stream/locales/nb-NO/strings.properties
browser/extensions/activity-stream/locales/ne-NP/strings.properties
browser/extensions/activity-stream/locales/nl/strings.properties
browser/extensions/activity-stream/locales/nn-NO/strings.properties
browser/extensions/activity-stream/locales/oc/strings.properties
browser/extensions/activity-stream/locales/pa-IN/strings.properties
browser/extensions/activity-stream/locales/pl/strings.properties
browser/extensions/activity-stream/locales/pt-BR/strings.properties
browser/extensions/activity-stream/locales/pt-PT/strings.properties
browser/extensions/activity-stream/locales/rm/strings.properties
browser/extensions/activity-stream/locales/ro/strings.properties
browser/extensions/activity-stream/locales/ru/strings.properties
browser/extensions/activity-stream/locales/si/strings.properties
browser/extensions/activity-stream/locales/sk/strings.properties
browser/extensions/activity-stream/locales/sl/strings.properties
browser/extensions/activity-stream/locales/sq/strings.properties
browser/extensions/activity-stream/locales/sr/strings.properties
browser/extensions/activity-stream/locales/sv-SE/strings.properties
browser/extensions/activity-stream/locales/ta/strings.properties
browser/extensions/activity-stream/locales/te/strings.properties
browser/extensions/activity-stream/locales/th/strings.properties
browser/extensions/activity-stream/locales/tl/strings.properties
browser/extensions/activity-stream/locales/tr/strings.properties
browser/extensions/activity-stream/locales/uk/strings.properties
browser/extensions/activity-stream/locales/ur/strings.properties
browser/extensions/activity-stream/locales/uz/strings.properties
browser/extensions/activity-stream/locales/vi/strings.properties
browser/extensions/activity-stream/locales/zh-CN/strings.properties
browser/extensions/activity-stream/locales/zh-TW/strings.properties
browser/extensions/activity-stream/mochitest.sh
browser/extensions/activity-stream/moz.build
browser/extensions/activity-stream/package-lock.json
browser/extensions/activity-stream/package.json
browser/extensions/activity-stream/prerendered/locales/ach/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ach/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ach/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/ach/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/ach/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/an/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/an/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/an/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/an/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/an/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/ar/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ar/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ar/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/ar/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/ar/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/ast/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ast/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ast/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/ast/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/ast/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/az/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/az/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/az/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/az/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/az/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/be/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/be/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/be/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/be/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/be/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/bg/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/bg/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/bg/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/bg/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/bg/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/bn-BD/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/bn-BD/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/bn-BD/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/bn-BD/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/bn-BD/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/bn-IN/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/bn-IN/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/bn-IN/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/bn-IN/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/bn-IN/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/br/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/br/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/br/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/br/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/br/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/bs/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/bs/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/bs/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/bs/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/bs/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/ca/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ca/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ca/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/ca/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/ca/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/cak/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/cak/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/cak/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/cak/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/cak/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/crh/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/crh/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/crh/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/crh/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/crh/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/cs/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/cs/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/cs/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/cs/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/cs/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/cy/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/cy/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/cy/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/cy/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/cy/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/da/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/da/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/da/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/da/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/da/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/de/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/de/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/de/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/de/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/de/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/dsb/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/dsb/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/dsb/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/dsb/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/dsb/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/el/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/el/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/el/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/el/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/el/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/en-CA/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/en-CA/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/en-CA/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/en-CA/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/en-CA/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/en-GB/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/en-GB/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/en-GB/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/en-GB/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/en-GB/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/en-US/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/en-US/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/en-US/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/en-US/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/en-US/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/eo/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/eo/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/eo/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/eo/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/eo/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/es-AR/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/es-AR/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/es-AR/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/es-AR/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/es-AR/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/es-CL/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/es-CL/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/es-CL/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/es-CL/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/es-CL/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/es-ES/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/es-ES/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/es-ES/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/es-ES/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/es-ES/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/es-MX/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/es-MX/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/es-MX/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/es-MX/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/es-MX/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/et/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/et/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/et/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/et/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/et/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/eu/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/eu/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/eu/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/eu/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/eu/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/fa/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/fa/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/fa/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/fa/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/fa/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/ff/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ff/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ff/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/ff/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/ff/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/fi/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/fi/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/fi/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/fi/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/fi/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/fr/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/fr/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/fr/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/fr/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/fr/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/fy-NL/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/fy-NL/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/fy-NL/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/fy-NL/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/fy-NL/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/ga-IE/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ga-IE/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ga-IE/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/ga-IE/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/ga-IE/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/gd/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/gd/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/gd/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/gd/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/gd/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/gl/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/gl/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/gl/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/gl/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/gl/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/gn/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/gn/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/gn/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/gn/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/gn/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/gu-IN/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/gu-IN/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/gu-IN/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/gu-IN/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/gu-IN/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/he/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/he/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/he/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/he/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/he/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/hi-IN/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/hi-IN/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/hi-IN/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/hi-IN/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/hi-IN/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/hr/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/hr/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/hr/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/hr/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/hr/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/hsb/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/hsb/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/hsb/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/hsb/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/hsb/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/hu/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/hu/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/hu/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/hu/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/hu/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/hy-AM/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/hy-AM/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/hy-AM/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/hy-AM/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/hy-AM/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/ia/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ia/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ia/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/ia/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/ia/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/id/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/id/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/id/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/id/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/id/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/it/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/it/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/it/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/it/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/it/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/ja-JP-mac/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ja-JP-mac/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ja-JP-mac/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/ja-JP-mac/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/ja-JP-mac/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/ja/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ja/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ja/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/ja/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/ja/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/ka/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ka/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ka/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/ka/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/ka/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/kab/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/kab/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/kab/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/kab/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/kab/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/kk/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/kk/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/kk/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/kk/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/kk/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/km/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/km/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/km/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/km/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/km/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/kn/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/kn/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/kn/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/kn/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/kn/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/ko/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ko/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ko/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/ko/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/ko/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/lij/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/lij/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/lij/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/lij/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/lij/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/lo/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/lo/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/lo/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/lo/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/lo/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/lt/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/lt/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/lt/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/lt/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/lt/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/ltg/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ltg/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ltg/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/ltg/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/ltg/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/lv/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/lv/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/lv/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/lv/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/lv/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/mai/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/mai/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/mai/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/mai/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/mai/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/mk/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/mk/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/mk/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/mk/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/mk/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/ml/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ml/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ml/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/ml/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/ml/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/mr/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/mr/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/mr/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/mr/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/mr/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/ms/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ms/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ms/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/ms/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/ms/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/my/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/my/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/my/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/my/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/my/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/nb-NO/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/nb-NO/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/nb-NO/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/nb-NO/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/nb-NO/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/ne-NP/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ne-NP/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ne-NP/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/ne-NP/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/ne-NP/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/nl/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/nl/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/nl/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/nl/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/nl/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/nn-NO/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/nn-NO/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/nn-NO/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/nn-NO/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/nn-NO/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/oc/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/oc/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/oc/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/oc/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/oc/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/pa-IN/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/pa-IN/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/pa-IN/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/pa-IN/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/pa-IN/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/pl/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/pl/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/pl/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/pl/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/pl/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/pt-BR/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/pt-BR/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/pt-BR/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/pt-BR/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/pt-BR/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/pt-PT/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/pt-PT/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/pt-PT/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/pt-PT/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/pt-PT/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/rm/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/rm/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/rm/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/rm/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/rm/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/ro/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ro/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ro/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/ro/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/ro/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/ru/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ru/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ru/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/ru/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/ru/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/si/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/si/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/si/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/si/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/si/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/sk/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/sk/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/sk/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/sk/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/sk/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/sl/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/sl/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/sl/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/sl/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/sl/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/sq/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/sq/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/sq/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/sq/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/sq/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/sr/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/sr/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/sr/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/sr/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/sr/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/sv-SE/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/sv-SE/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/sv-SE/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/sv-SE/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/sv-SE/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/ta/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ta/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ta/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/ta/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/ta/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/te/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/te/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/te/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/te/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/te/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/th/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/th/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/th/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/th/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/th/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/tl/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/tl/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/tl/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/tl/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/tl/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/tr/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/tr/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/tr/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/tr/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/tr/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/uk/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/uk/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/uk/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/uk/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/uk/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/ur/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ur/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/ur/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/ur/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/ur/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/uz/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/uz/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/uz/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/uz/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/uz/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/vi/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/vi/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/vi/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/vi/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/vi/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/zh-CN/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/zh-CN/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/zh-CN/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/zh-CN/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/zh-CN/activity-stream.html
browser/extensions/activity-stream/prerendered/locales/zh-TW/activity-stream-noscripts.html
browser/extensions/activity-stream/prerendered/locales/zh-TW/activity-stream-prerendered-noscripts.html
browser/extensions/activity-stream/prerendered/locales/zh-TW/activity-stream-prerendered.html
browser/extensions/activity-stream/prerendered/locales/zh-TW/activity-stream-strings.js
browser/extensions/activity-stream/prerendered/locales/zh-TW/activity-stream.html
browser/extensions/activity-stream/prerendered/static/activity-stream-debug-noscripts.html
browser/extensions/activity-stream/prerendered/static/activity-stream-debug.html
browser/extensions/activity-stream/prerendered/static/activity-stream-initial-state.js
browser/extensions/activity-stream/prerendered/static/activity-stream-prerendered-debug-noscripts.html
browser/extensions/activity-stream/prerendered/static/activity-stream-prerendered-debug.html
browser/extensions/activity-stream/test/.eslintrc.js
browser/extensions/activity-stream/test/functional/mochitest/.eslintrc.js
browser/extensions/activity-stream/test/functional/mochitest/blue_page.html
browser/extensions/activity-stream/test/functional/mochitest/browser.ini
browser/extensions/activity-stream/test/functional/mochitest/browser_as_load_location.js
browser/extensions/activity-stream/test/functional/mochitest/browser_as_render.js
browser/extensions/activity-stream/test/functional/mochitest/browser_asrouter_targeting.js
browser/extensions/activity-stream/test/functional/mochitest/browser_getScreenshots.js
browser/extensions/activity-stream/test/functional/mochitest/browser_highlights_section.js
browser/extensions/activity-stream/test/functional/mochitest/browser_topsites_contextMenu_options.js
browser/extensions/activity-stream/test/functional/mochitest/browser_topsites_section.js
browser/extensions/activity-stream/test/functional/mochitest/head.js
browser/extensions/activity-stream/test/schemas/pings.js
browser/extensions/activity-stream/test/unit/activity-stream-prerender.test.jsx
browser/extensions/activity-stream/test/unit/asrouter/ASRouter.test.js
browser/extensions/activity-stream/test/unit/asrouter/ASRouterFeed.test.js
browser/extensions/activity-stream/test/unit/asrouter/ASRouterTargeting.test.js
browser/extensions/activity-stream/test/unit/asrouter/MessageLoaderUtils.test.js
browser/extensions/activity-stream/test/unit/asrouter/asrouter-content.test.jsx
browser/extensions/activity-stream/test/unit/asrouter/constants.js
browser/extensions/activity-stream/test/unit/asrouter/template-utils.test.js
browser/extensions/activity-stream/test/unit/asrouter/templates/SimpleSnippet.test.jsx
browser/extensions/activity-stream/test/unit/common/Actions.test.js
browser/extensions/activity-stream/test/unit/common/Dedupe.test.js
browser/extensions/activity-stream/test/unit/common/PerfService.test.js
browser/extensions/activity-stream/test/unit/common/PrerenderData.test.js
browser/extensions/activity-stream/test/unit/common/Reducers.test.js
browser/extensions/activity-stream/test/unit/content-src/components/Base.test.jsx
browser/extensions/activity-stream/test/unit/content-src/components/Card.test.jsx
browser/extensions/activity-stream/test/unit/content-src/components/CollapsibleSection.test.jsx
browser/extensions/activity-stream/test/unit/content-src/components/ComponentPerfTimer.test.jsx
browser/extensions/activity-stream/test/unit/content-src/components/ConfirmDialog.test.jsx
browser/extensions/activity-stream/test/unit/content-src/components/ContextMenu.test.jsx
browser/extensions/activity-stream/test/unit/content-src/components/ErrorBoundary.test.jsx
browser/extensions/activity-stream/test/unit/content-src/components/LinkMenu.test.jsx
browser/extensions/activity-stream/test/unit/content-src/components/ManualMigration.test.jsx
browser/extensions/activity-stream/test/unit/content-src/components/Search.test.jsx
browser/extensions/activity-stream/test/unit/content-src/components/SectionMenu.test.jsx
browser/extensions/activity-stream/test/unit/content-src/components/Sections.test.jsx
browser/extensions/activity-stream/test/unit/content-src/components/StartupOverlay.test.jsx
browser/extensions/activity-stream/test/unit/content-src/components/TopSites.test.jsx
browser/extensions/activity-stream/test/unit/content-src/components/Topics.test.jsx
browser/extensions/activity-stream/test/unit/content-src/lib/detect-user-session-start.test.js
browser/extensions/activity-stream/test/unit/content-src/lib/init-store.test.js
browser/extensions/activity-stream/test/unit/content-src/lib/screenshot-utils.test.js
browser/extensions/activity-stream/test/unit/content-src/lib/snippets.test.js
browser/extensions/activity-stream/test/unit/lib/AboutPreferences.test.js
browser/extensions/activity-stream/test/unit/lib/ActivityStream.test.js
browser/extensions/activity-stream/test/unit/lib/ActivityStreamMessageChannel.test.js
browser/extensions/activity-stream/test/unit/lib/ActivityStreamPrefs.test.js
browser/extensions/activity-stream/test/unit/lib/ActivityStreamStorage.test.js
browser/extensions/activity-stream/test/unit/lib/DownloadsManager.test.js
browser/extensions/activity-stream/test/unit/lib/FaviconFeed.test.js
browser/extensions/activity-stream/test/unit/lib/FilterAdult.test.js
browser/extensions/activity-stream/test/unit/lib/HighlightsFeed.test.js
browser/extensions/activity-stream/test/unit/lib/ManualMigration.test.js
browser/extensions/activity-stream/test/unit/lib/NewTabInit.test.js
browser/extensions/activity-stream/test/unit/lib/PersistentCache.test.js
browser/extensions/activity-stream/test/unit/lib/PlacesFeed.test.js
browser/extensions/activity-stream/test/unit/lib/PrefsFeed.test.js
browser/extensions/activity-stream/test/unit/lib/Screenshots.test.js
browser/extensions/activity-stream/test/unit/lib/SectionsManager.test.js
browser/extensions/activity-stream/test/unit/lib/ShortUrl.test.js
browser/extensions/activity-stream/test/unit/lib/SnippetsFeed.test.js
browser/extensions/activity-stream/test/unit/lib/Store.test.js
browser/extensions/activity-stream/test/unit/lib/SystemTickFeed.test.js
browser/extensions/activity-stream/test/unit/lib/TelemetryFeed.test.js
browser/extensions/activity-stream/test/unit/lib/TippyTopProvider.test.js
browser/extensions/activity-stream/test/unit/lib/TopSitesFeed.test.js
browser/extensions/activity-stream/test/unit/lib/TopStoriesFeed.test.js
browser/extensions/activity-stream/test/unit/lib/UTEventReporting.test.js
browser/extensions/activity-stream/test/unit/lib/UserDomainAffinityProvider.test.js
browser/extensions/activity-stream/test/unit/unit-entry.js
browser/extensions/activity-stream/test/unit/utils.js
browser/extensions/activity-stream/vendor/PROP_TYPES_LICENSE
browser/extensions/activity-stream/vendor/REACT_AND_REACT_DOM_LICENSE
browser/extensions/activity-stream/vendor/REACT_INTL_LICENSE
browser/extensions/activity-stream/vendor/REACT_REDUX_LICENSE
browser/extensions/activity-stream/vendor/REDUX_LICENSE
browser/extensions/activity-stream/vendor/Redux.jsm
browser/extensions/activity-stream/vendor/prop-types.js
browser/extensions/activity-stream/vendor/react-dev.js
browser/extensions/activity-stream/vendor/react-dom-dev.js
browser/extensions/activity-stream/vendor/react-dom.js
browser/extensions/activity-stream/vendor/react-intl.js
browser/extensions/activity-stream/vendor/react-redux.js
browser/extensions/activity-stream/vendor/react.js
browser/extensions/activity-stream/vendor/redux.js
browser/extensions/activity-stream/webpack.prerender.config.js
browser/extensions/activity-stream/webpack.system-addon.config.js
browser/extensions/activity-stream/yamscripts.yml
browser/extensions/moz.build
dom/interfaces/base/nsIIdleObserver.idl
python/mozbuild/mozbuild/test/codecoverage/test_lcov_rewrite.py
testing/runtimes/mochitest-browser-chrome-e10s.runtimes.json
testing/runtimes/mochitest-browser-chrome.runtimes.json
toolkit/content/license.html
tools/lint/codespell.yml
--- a/.eslintignore
+++ b/.eslintignore
@@ -85,17 +85,17 @@ browser/components/translation/cld2/**
 browser/extensions/followonsearch/**
 browser/extensions/screenshots/**
 browser/extensions/pdfjs/content/build**
 browser/extensions/pdfjs/content/web**
 # generated or library files in pocket
 browser/extensions/pocket/content/panels/js/tmpl.js
 browser/extensions/pocket/content/panels/js/vendor/**
 # Activity Stream has incompatible eslintrc. `npm run lint` from its directory
-browser/extensions/activity-stream/**
+browser/components/newtab/**
 # The only file in browser/locales/ is pre-processed.
 browser/locales/**
 # imported from chromium
 browser/extensions/mortar/**
 # Generated data files
 browser/extensions/formautofill/phonenumberutils/PhoneNumberMetaData.jsm
 
 # devtools/ exclusions
--- a/CLOBBER
+++ b/CLOBBER
@@ -17,9 +17,9 @@
 #
 # Modifying this file will now automatically clobber the buildbot machines \o/
 #
 
 # Are you updating CLOBBER because you think it's needed for your WebIDL
 # changes to stick? As of bug 928195, this shouldn't be necessary! Please
 # don't change CLOBBER for WebIDL changes any more.
 
-Bug 1371485 - Moving gyp requires a clobber.
+Bug 1474414 - Moving Activity Stream out of system-addon requires a clobber.
--- a/Makefile.in
+++ b/Makefile.in
@@ -264,26 +264,23 @@ ifndef MOZ_AUTOMATION
 prepsymbolsarchive: recurse_syms
 endif
 
 .PHONY: symbolsfullarchive
 symbolsfullarchive: prepsymbolsarchive
 	$(RM) '$(DIST)/$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip'
 	$(call py_action,symbols_archive,'$(DIST)/$(PKG_PATH)$(SYMBOL_FULL_ARCHIVE_BASENAME).zip' \
                                      $(abspath $(DIST)/crashreporter-symbols) \
-                                     --exclude '*test*' \
-                                     --exclude '*Test*' \
-                                     --compress '**/*.sym')
+                                     --full-archive)
 
 .PHONY: symbolsarchive
 symbolsarchive: prepsymbolsarchive
 	$(RM) '$(DIST)/$(PKG_PATH)$(SYMBOL_ARCHIVE_BASENAME).zip'
 	$(call py_action,symbols_archive,'$(DIST)/$(PKG_PATH)$(SYMBOL_ARCHIVE_BASENAME).zip' \
-                                     $(abspath $(DIST)/crashreporter-symbols) \
-                                     --include '**/*.sym')
+                                     $(abspath $(DIST)/crashreporter-symbols))
 
 ifdef MOZ_CRASHREPORTER
 buildsymbols: symbolsfullarchive symbolsarchive
 else
 buildsymbols:
 endif
 
 uploadsymbols:
--- a/browser/base/content/test/performance/browser_preferences_usage.js
+++ b/browser/base/content/test/performance/browser_preferences_usage.js
@@ -88,17 +88,17 @@ add_task(async function startup() {
     "layout.css.dpi": {
       min: 45,
       max: 75,
     },
     "network.loadinfo.skip_type_assertion": {
       max: 650,
     },
     "extensions.getAddons.cache.enabled": {
-      min: 9,
+      min: 8,
       max: 55,
     },
   };
 
   let startupRecorder = Cc["@mozilla.org/test/startuprecorder;1"].getService().wrappedJSObject;
   await startupRecorder.done;
 
   ok(startupRecorder.data.prefStats, "startupRecorder has prefStats");
--- a/browser/base/content/test/tabs/browser_isLocalAboutURI.js
+++ b/browser/base/content/test/tabs/browser_isLocalAboutURI.js
@@ -28,17 +28,17 @@ add_task(function test_URI() {
 
 add_task(function test_URI_with_resolved() {
   const check = (spec, resolvedSpec, expect, description) => {
     const URI = Services.io.newURI(spec);
     const resolvedURI = Services.io.newURI(resolvedSpec);
     is(gBrowser._isLocalAboutURI(URI, resolvedURI), expect, description);
   };
   check("about:newtab",
-    "jar:file:///Applications/Firefox.app/Contents/Resources/browser/features/activity-stream@mozilla.org.xpi!/chrome/content/data/content/activity-stream.html",
+    "jar:file:///Applications/Firefox.app/Contents/Resources/browser/omni.ja!/chrome/browser/res/activity-stream/prerendered/en-US/activity-stream.html",
     true,
     "about:newtab with jar is local");
   check("about:newtab",
     "file:///mozilla-central/browser/base/content/newtab/newTab.xhtml",
     true,
     "about:newtab with file is local");
   check("about:newtab",
     "https://www.mozilla.org/newtab",
rename from browser/extensions/activity-stream/.eslintignore
rename to browser/components/newtab/.eslintignore
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/.eslintrc.js
@@ -0,0 +1,235 @@
+module.exports = {
+  // When adding items to this file please check for effects on sub-directories.
+  "parserOptions": {
+    "ecmaFeatures": {
+      "jsx": true
+    },
+    "sourceType": "module"
+  },
+  "env": {
+    "node": true
+  },
+  "plugins": [
+    "import", // require("eslint-plugin-import")
+    "json", // require("eslint-plugin-json")
+    "promise", // require("eslint-plugin-promise")
+    "react" // require("eslint-plugin-react")
+  ],
+  "extends": [
+    "eslint:recommended",
+    "plugin:mozilla/recommended" // require("eslint-plugin-mozilla")
+  ],
+  "globals": {
+    // Remove this when m-c updates their eslint: See https://github.com/mozilla/activity-stream/pull/4219
+    "RPMSendAsyncMessage": true
+  },
+  "overrides": [{
+    // Use a configuration that's more appropriate for JSMs
+    "files": "**/*.jsm",
+    "parserOptions": {
+      "sourceType": "script"
+    },
+    "env": {
+      "node": false
+    },
+    "rules": {
+      "no-implicit-globals": 0
+    }
+  }],
+  "rules": {
+    "promise/catch-or-return": 2,
+    "promise/param-names": 2,
+
+    "react/jsx-boolean-value": [2, "always"],
+    "react/jsx-closing-bracket-location": [2, "after-props"],
+    "react/jsx-curly-spacing": [2, "never"],
+    "react/jsx-equals-spacing": [2, "never"],
+    "react/jsx-key": 2,
+    "react/jsx-no-bind": 2,
+    "react/jsx-no-comment-textnodes": 2,
+    "react/jsx-no-duplicate-props": 2,
+    "react/jsx-no-target-blank": 2,
+    "react/jsx-no-undef": 2,
+    "react/jsx-pascal-case": 2,
+    "react/jsx-space-before-closing": [2, "always"],
+    "react/jsx-uses-react": 2,
+    "react/jsx-uses-vars": 2,
+    "react/jsx-wrap-multilines": 2,
+    "react/no-access-state-in-setstate": 2,
+    "react/no-danger": 2,
+    "react/no-deprecated": 2,
+    "react/no-did-mount-set-state": 2,
+    "react/no-did-update-set-state": 2,
+    "react/no-direct-mutation-state": 2,
+    "react/no-is-mounted": 2,
+    "react/no-unknown-property": 2,
+    "react/require-render-return": 2,
+    "react/self-closing-comp": 2,
+
+    "accessor-pairs": [2, {"setWithoutGet": true, "getWithoutSet": false}],
+    "array-bracket-newline": [2, "consistent"],
+    "array-bracket-spacing": [2, "never"],
+    "array-callback-return": 2,
+    "array-element-newline": 0,
+    "arrow-body-style": [2, "as-needed"],
+    "arrow-parens": [2, "as-needed"],
+    "block-scoped-var": 2,
+    "callback-return": 0,
+    "camelcase": 0,
+    "capitalized-comments": 0,
+    "class-methods-use-this": 0,
+    "comma-dangle": [2, "never"],
+    "consistent-this": [2, "use-bind"],
+    "curly": [2, "all"],
+    "default-case": 0,
+    "dot-location": [2, "property"],
+    "eqeqeq": 2,
+    "for-direction": 2,
+    "func-name-matching": 2,
+    "func-names": 0,
+    "func-style": 0,
+    "function-paren-newline": 0,
+    "getter-return": 2,
+    "global-require": 0,
+    "guard-for-in": 2,
+    "handle-callback-err": 2,
+    "id-blacklist": 0,
+    "id-length": 0,
+    "id-match": 0,
+    "implicit-arrow-linebreak": 0,
+    // XXX Switch back to indent once mozilla-central has decided what it is using.
+    "indent": 0,
+    "indent-legacy": ["error", 2, {"SwitchCase": 1}],
+    "init-declarations": 0,
+    "jsx-quotes": [2, "prefer-double"],
+    "line-comment-position": 0,
+    "lines-around-comment": ["error", {
+      "allowClassStart": true,
+      "allowObjectStart": true,
+      "beforeBlockComment": true
+    }],
+    "lines-between-class-members": 2,
+    "max-depth": [2, 4],
+    "max-len": 0,
+    "max-lines": 0,
+    "max-nested-callbacks": [2, 4],
+    "max-params": [2, 6],
+    "max-statements": [2, 50],
+    "max-statements-per-line": [2, {"max": 2}],
+    "multiline-comment-style": 0,
+    "multiline-ternary": 0,
+    "new-cap": [2, {"newIsCap": true, "capIsNew": false}],
+    "new-parens": 2,
+    "newline-after-var": 0,
+    "newline-before-return": 0,
+    "newline-per-chained-call": [2, {"ignoreChainWithDepth": 3}],
+    "no-alert": 2,
+    "no-await-in-loop": 0,
+    "no-bitwise": 0,
+    "no-buffer-constructor": 2,
+    "no-catch-shadow": 2,
+    "no-confusing-arrow": [2, {"allowParens": true}],
+    "no-console": 1,
+    "no-continue": 0,
+    "no-div-regex": 2,
+    "no-duplicate-imports": 2,
+    "no-empty-function": 0,
+    "no-eq-null": 2,
+    "no-extend-native": 2,
+    "no-extra-label": 2,
+    "no-extra-parens": 0,
+    "no-floating-decimal": 2,
+    "no-implicit-coercion": [2, {"allow": ["!!"]}],
+    "no-implicit-globals": 2,
+    "no-inline-comments": 0,
+    "no-invalid-this": 0,
+    "no-label-var": 2,
+    "no-loop-func": 2,
+    "no-magic-numbers": 0,
+    "no-mixed-operators": [2, {"allowSamePrecedence": true, "groups": [["&", "|", "^", "~", "<<", ">>", ">>>"], ["==", "!=", "===", "!==", ">", ">=", "<", "<="], ["&&", "||"], ["in", "instanceof"]]}],
+    "no-mixed-requires": 2,
+    "no-multi-assign": 2,
+    "no-multi-str": 2,
+    "no-multiple-empty-lines": [2, {"max": 1, "maxBOF": 0, "maxEOF": 0}],
+    "no-negated-condition": 0,
+    "no-negated-in-lhs": 2,
+    "no-new": 2,
+    "no-new-func": 2,
+    "no-new-require": 2,
+    "no-octal-escape": 2,
+    "no-param-reassign": 2,
+    "no-path-concat": 2,
+    "no-plusplus": 0,
+    "no-process-env": 0,
+    "no-process-exit": 2,
+    "no-proto": 2,
+    "no-prototype-builtins": 2,
+    "no-restricted-globals": 0,
+    "no-restricted-imports": 0,
+    "no-restricted-modules": 0,
+    "no-restricted-properties": 0,
+    "no-restricted-syntax": 0,
+    "no-return-assign": [2, "except-parens"],
+    "no-script-url": 2,
+    "no-sequences": 2,
+    "no-shadow": 2,
+    "no-spaced-func": 2,
+    "no-sync": 0,
+    "no-template-curly-in-string": 2,
+    "no-ternary": 0,
+    "no-throw-literal": 2,
+    "no-undef-init": 2,
+    "no-undefined": 0,
+    "no-underscore-dangle": 0,
+    "no-unmodified-loop-condition": 2,
+    "no-unused-expressions": 2,
+    "no-use-before-define": 2,
+    "no-useless-computed-key": 2,
+    "no-useless-constructor": 2,
+    "no-useless-rename": 2,
+    "no-var": 2,
+    "no-void": 2,
+    "no-warning-comments": 0, // TODO: Change to `1`?
+    "nonblock-statement-body-position": 2,
+    "object-curly-newline": [2, {"multiline": true}],
+    "object-curly-spacing": [2, "never"],
+    "object-property-newline": [2, {"allowMultiplePropertiesPerLine": true}],
+    "one-var": [2, "never"],
+    "one-var-declaration-per-line": [2, "initializations"],
+    "operator-assignment": [2, "always"],
+    "operator-linebreak": [2, "after"],
+    "padded-blocks": [2, "never"],
+    "padding-line-between-statements": 0,
+    "prefer-arrow-callback": ["error", {"allowNamedFunctions": true}],
+    "prefer-const": 0, // TODO: Change to `1`?
+    "prefer-destructuring": [2, {"AssignmentExpression": {"array": true}, "VariableDeclarator": {"array": true, "object": true}}],
+    "prefer-numeric-literals": 2,
+    "prefer-promise-reject-errors": 2,
+    "prefer-reflect": 0,
+    "prefer-rest-params": 2,
+    "prefer-spread": 2,
+    "prefer-template": 2,
+    "quote-props": [2, "consistent"],
+    "radix": [2, "always"],
+    "require-await": 2,
+    "require-jsdoc": 0,
+    "semi-spacing": [2, {"before": false, "after": true}],
+    "semi-style": 2,
+    "sort-imports": [2, {"ignoreCase": true}],
+    "sort-keys": 0,
+    "sort-vars": 2,
+    "space-in-parens": [2, "never"],
+    "strict": 0,
+    "switch-colon-spacing": 2,
+    "symbol-description": 2,
+    "template-curly-spacing": [2, "never"],
+    "template-tag-spacing": 2,
+    "unicode-bom": [2, "never"],
+    "valid-jsdoc": [0, {"requireReturn": false, "requireParamDescription": false, "requireReturnDescription": false}],
+    "vars-on-top": 2,
+    "wrap-iife": [2, "inside"],
+    "wrap-regex": 0,
+    "yield-star-spacing": [2, "after"],
+    "yoda": [2, "never"]
+  }
+};
rename from browser/extensions/activity-stream/.mcignore
rename to browser/components/newtab/.mcignore
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/.nvmrc
@@ -0,0 +1,1 @@
+8.*
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/.sass-lint.yml
@@ -0,0 +1,26 @@
+options:
+  merge-default-rules: true
+  max-warnings: 0
+
+files:
+  include: 'content-src/**/*.scss'
+
+rules:
+  class-name-format: 0
+  extends-before-declarations: 2
+  extends-before-mixins: 2
+  force-element-nesting: 0
+  force-pseudo-nesting: 0
+  hex-notation: [2, {style: uppercase}]
+  indentation: [2, {size: 2}]
+  leading-zero: [2, {include: true}]
+  mixins-before-declarations: [2, {exclude: [breakpoint, mq]}]
+  nesting-depth: [2, {max-depth: 4}]
+  no-debug: 1
+  no-duplicate-properties: 2
+  no-misspelled-properties: [2, {extra-properties: [-moz-context-properties]}]
+  no-url-domains: 0
+  no-vendor-prefixes: 0
+  no-warn: 1
+  placeholder-in-extend: 2
+  property-sort-order: 0
rename from browser/extensions/activity-stream/.taskcluster.yml
rename to browser/components/newtab/.taskcluster.yml
rename from browser/extensions/activity-stream/.travis.yml
rename to browser/components/newtab/.travis.yml
rename from browser/extensions/activity-stream/CODEOWNERS
rename to browser/components/newtab/CODEOWNERS
rename from browser/extensions/activity-stream/LICENSE
rename to browser/components/newtab/LICENSE
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/README.md
@@ -0,0 +1,24 @@
+# activity-stream
+
+[![Task Status](https://github.taskcluster.net/v1/repository/mozilla/activity-stream/master/badge.svg)](https://github.taskcluster.net/v1/repository/mozilla/activity-stream/master/latest)
+
+This system add-on replaces the new tab page in Firefox with a new design and
+functionality as part of the Activity Stream project.
+
+The files in this directory, including vendor dependencies, are imported from the
+system-addon directory in https://github.com/mozilla/activity-stream.
+
+Read [docs/v2-system-addon](https://github.com/mozilla/activity-stream/tree/master/docs/v2-system-addon/1.GETTING_STARTED.md) for more detail.
+
+## Where should I file bugs?
+
+We regularly check the ActivityStream:NewTab component on Bugzilla.
+
+## For Developers
+
+If you are interested in contributing, take a look at [this guide](contributing.md) on where to find us and how to contribute,
+and [this guide](docs/v2-system-addon/1.GETTING_STARTED.md) for getting your development environment set up.
+
+## For Localizers
+
+Activity Stream localization is managed via [Pontoon](https://pontoon.mozilla.org/projects/activity-stream-new-tab/), not direct pull requests to the repository. If you want to fix a typo, add a new language, or simply know more about localization, please get in touch with the [existing localization team](https://pontoon.mozilla.org/teams/) for your language, or Mozilla’s [l10n-drivers](https://wiki.mozilla.org/L10n:Mozilla_Team#Mozilla_Corporation) for guidance.
rename from browser/extensions/activity-stream/bin/download-firefox-artifact
rename to browser/components/newtab/bin/download-firefox-artifact
rename from browser/extensions/activity-stream/bin/download-firefox-travis.sh
rename to browser/components/newtab/bin/download-firefox-travis.sh
rename from browser/extensions/activity-stream/bin/locales.js
rename to browser/components/newtab/bin/locales.js
rename from browser/extensions/activity-stream/bin/prepare-mochitests-dev
rename to browser/components/newtab/bin/prepare-mochitests-dev
rename from browser/extensions/activity-stream/bin/process-system-addon-for-package.js
rename to browser/components/newtab/bin/process-system-addon-for-package.js
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/bin/render-activity-stream-html.js
@@ -0,0 +1,252 @@
+ /* eslint-disable no-console */
+const fs = require("fs");
+const {mkdir} = require("shelljs");
+const path = require("path");
+
+// Note: this file is generated by webpack from content-src/activity-stream-prerender.jsx
+const {prerender} = require("./prerender");
+
+const {CENTRAL_LOCALES, DEFAULT_LOCALE} = require("./locales");
+
+// Note: DEFAULT_OPTIONS.baseUrl should match BASE_URL in aboutNewTabService.js
+//       in mozilla-central.
+const DEFAULT_OPTIONS = {
+  addonPath: "..",
+  baseUrl: "resource://activity-stream/"
+};
+
+// Locales that should be displayed RTL
+const RTL_LIST = ["ar", "he", "fa", "ur"];
+
+/**
+ * Get the language part of the locale.
+ */
+function getLanguage(locale) {
+  return locale.split("-")[0];
+}
+
+/**
+ * Get the best strings for a single provided locale using similar locales and
+ * DEFAULT_LOCALE as fallbacks.
+ */
+function getStrings(locale, allStrings) {
+  const availableLocales = Object.keys(allStrings);
+
+  const language = getLanguage(locale);
+  const similarLocales = availableLocales.filter(other =>
+    other !== locale && getLanguage(other) === language);
+
+  // Rank locales from least desired to most desired
+  const localeFallbacks = [DEFAULT_LOCALE, ...similarLocales, locale];
+
+  // Get strings from each locale replacing with those from more desired ones
+  return Object.assign({}, ...localeFallbacks.map(l => allStrings[l]));
+}
+
+/**
+ * Get the text direction of the locale.
+ */
+function getTextDirection(locale) {
+  return RTL_LIST.includes(locale.split("-")[0]) ? "rtl" : "ltr";
+}
+
+/**
+ * templateHTML - Generates HTML for activity stream, given some options and
+ * prerendered HTML if necessary.
+ *
+ * @param  {obj} options
+ *         {str} options.locale         The locale to render in lang="" attribute
+ *         {str} options.direction      The language direction to render in dir="" attribute
+ *         {str} options.baseUrl        The base URL for all local assets
+ *         {bool} options.debug         Should we use dev versions of JS libraries?
+ *         {bool} options.noscripts     Should we include scripts in the prerendered files?
+ * @param  {str} html    The prerendered HTML created with React.renderToString (optional)
+ * @return {str}         An HTML document as a string
+ */
+function templateHTML(options, html) {
+  const isPrerendered = !!html;
+  const debugString = options.debug ? "-dev" : "";
+  const scripts = [
+    "chrome://browser/content/contentSearchUI.js",
+    "chrome://browser/content/contentTheme.js",
+    `${options.baseUrl}vendor/react${debugString}.js`,
+    `${options.baseUrl}vendor/react-dom${debugString}.js`,
+    `${options.baseUrl}vendor/prop-types.js`,
+    `${options.baseUrl}vendor/react-intl.js`,
+    `${options.baseUrl}vendor/redux.js`,
+    `${options.baseUrl}vendor/react-redux.js`,
+    `${options.baseUrl}prerendered/${options.locale}/activity-stream-strings.js`,
+    `${options.baseUrl}data/content/activity-stream.bundle.js`
+  ];
+  if (isPrerendered) {
+    scripts.unshift(`${options.baseUrl}prerendered/static/activity-stream-initial-state.js`);
+  }
+  const scriptTag = `
+    <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 ${JSON.stringify(scripts, null, 2)}) {
+  // These dynamically inserted scripts by default are async, but we need them
+  // to load in the desired order (i.e., bundle last).
+  const script = document.body.appendChild(document.createElement("script"));
+  script.async = false;
+  script.src = src;
+}
+    </script>`;
+  return `<!doctype html>
+<html lang="${options.locale}" dir="${options.direction}">
+  <head>
+    <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>${options.strings.newtab_page_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="${options.baseUrl}css/activity-stream.css" />
+  </head>
+  <body class="activity-stream">
+    <div id="root">${isPrerendered ? html : ""}</div>
+    <div id="snippets-container">
+      <div id="snippets"></div>
+    </div>${options.noscripts ? "" : scriptTag}
+  </body>
+</html>
+`;
+}
+
+/**
+ * templateJs - Generates a js file that passes the initial state of the prerendered
+ * DOM to the React version. This is necessary to ensure the checksum matches when
+ * React mounts so that it can attach to the prerendered elements instead of blowing
+ * them away.
+ *
+ * Note that this may no longer be necessary in React 16 and we should review whether
+ * it is still necessary.
+ *
+ * @param  {string} name The name of the global to expose
+ * @param  {string} desc Extra description to include in a js comment
+ * @param  {obj}   state The data to expose as a window global
+ * @return {str}         The js file as a string
+ */
+function templateJs(name, desc, state) {
+  return `// Note - this is a generated ${desc} file.
+window.${name} = ${JSON.stringify(state, null, 2)};
+`;
+}
+
+/**
+ * writeFiles - Writes to the desired files the result of a template given
+ * various prerendered data and options.
+ *
+ * @param {string} name          Something to identify in the console
+ * @param {string} destPath      Path to write the files to
+ * @param {Map}    filesMap      Mapping of a string file name to templater
+ * @param {Object} prerenderData Contains the html and state
+ * @param {Object} options       Various options for the templater
+ */
+function writeFiles(name, destPath, filesMap, {html, state}, options) {
+  for (const [file, templater] of filesMap) {
+    fs.writeFileSync(path.join(destPath, file), templater({html, options, state}));
+  }
+  console.log("\x1b[32m", `✓ ${name}`, "\x1b[0m");
+}
+
+const STATIC_FILES = new Map([
+  ["activity-stream-debug.html", ({options}) => templateHTML(options)],
+  ["activity-stream-debug-noscripts.html", ({options}) => templateHTML(Object.assign({}, options, {noscripts: true}))],
+  ["activity-stream-initial-state.js", ({state}) => templateJs("gActivityStreamPrerenderedState", "static", state)],
+  ["activity-stream-prerendered-debug.html", ({html, options}) => templateHTML(options, html)],
+  ["activity-stream-prerendered-debug-noscripts.html", ({html, options}) => templateHTML(Object.assign({}, options, {noscripts: true}), html)]
+]);
+
+const LOCALIZED_FILES = new Map([
+  ["activity-stream-prerendered.html", ({html, options}) => templateHTML(options, html)],
+  ["activity-stream-prerendered-noscripts.html", ({html, options}) => templateHTML(Object.assign({}, options, {noscripts: true}), html)],
+  ["activity-stream-strings.js", ({options: {locale, strings}}) => templateJs("gActivityStreamStrings", locale, strings)],
+  ["activity-stream.html", ({options}) => templateHTML(options)],
+  ["activity-stream-noscripts.html", ({options}) => templateHTML(Object.assign({}, options, {noscripts: true}))]
+]);
+
+/**
+ * main - Parses command line arguments, generates html and js with templates,
+ *        and writes files to their specified locations.
+ */
+function main() { // eslint-disable-line max-statements
+  // This code parses command line arguments passed to this script.
+  // Note: process.argv.slice(2) is necessary because the first two items in
+  // process.argv are paths
+  const args = require("minimist")(process.argv.slice(2), {
+    alias: {
+      addonPath: "a",
+      baseUrl: "b"
+    }
+  });
+
+  const baseOptions = Object.assign({debug: false}, DEFAULT_OPTIONS, args || {});
+  const addonPath = path.resolve(__dirname, baseOptions.addonPath);
+  const allStrings = require(`${baseOptions.addonPath}/data/locales.json`);
+  const extraLocales = Object.keys(allStrings).filter(locale =>
+    locale !== DEFAULT_LOCALE && !CENTRAL_LOCALES.includes(locale));
+
+  const prerenderedPath = path.join(addonPath, "prerendered");
+  console.log(`Writing prerendered files to individual directories under ${prerenderedPath}:`);
+
+  // Save default locale's strings to compare against other locales' strings
+  let defaultStrings;
+  let langStrings;
+  const isSubset = (strings, existing) => existing &&
+    Object.keys(strings).every(key => strings[key] === existing[key]);
+
+  // Process the default locale first then all the ones from mozilla-central
+  const localizedLocales = [];
+  const skippedLocales = [];
+  for (const locale of [DEFAULT_LOCALE, ...CENTRAL_LOCALES]) {
+    // Skip the locale if it would have resulted in duplicate packaged files
+    const strings = getStrings(locale, allStrings);
+    if (isSubset(strings, defaultStrings) || isSubset(strings, langStrings)) {
+      skippedLocales.push(locale);
+      continue;
+    }
+
+    const prerenderData  = prerender(locale, strings);
+    const options = Object.assign({}, baseOptions, {
+      direction: getTextDirection(locale),
+      locale,
+      strings
+    });
+
+    // Put locale-specific files in their own directory
+    const localePath = path.join(prerenderedPath, "locales", locale);
+    mkdir("-p", localePath);
+    writeFiles(locale, localePath, LOCALIZED_FILES, prerenderData, options);
+
+    // Only write static files once for the default locale
+    if (locale === DEFAULT_LOCALE) {
+      const staticPath = path.join(prerenderedPath, "static");
+      mkdir("-p", staticPath);
+      writeFiles(`${locale} (static)`, staticPath, STATIC_FILES, prerenderData,
+        Object.assign({}, options, {debug: true}));
+
+      // Save the default strings to compare against other locales' strings
+      defaultStrings = strings;
+    }
+
+    // Save the language's strings to maybe reuse for the next similar locales
+    if (getLanguage(locale) === locale) {
+      langStrings = strings;
+    }
+
+    localizedLocales.push(locale);
+  }
+
+  if (skippedLocales.length) {
+    console.log("\x1b[33m", `Skipped the following locales because they use the same strings as ${DEFAULT_LOCALE} or its language locale: ${skippedLocales.join(", ")}`, "\x1b[0m");
+  }
+  if (extraLocales.length) {
+    console.log("\x1b[33m", `Skipped the following locales because they are not in CENTRAL_LOCALES: ${extraLocales.join(", ")}`, "\x1b[0m");
+  }
+
+  // Provide some help to copy/paste locales if tests are failing
+  console.log(`\nIf aboutNewTabService tests are failing for unexpected locales, make sure its list is updated:\nconst ACTIVITY_STREAM_LOCALES = "${localizedLocales.join(" ")}".split(" ");`);
+}
+
+main();
new file mode 100755
--- /dev/null
+++ b/browser/components/newtab/bin/strings-import.js
@@ -0,0 +1,88 @@
+#! /usr/bin/env node
+"use strict";
+
+/* eslint-disable no-console */
+const fetch = require("node-fetch");
+
+/* globals cd, ls, mkdir, rm, ShellString */
+require("shelljs/global");
+
+const {CENTRAL_LOCALES, DEFAULT_LOCALE} = require("./locales");
+const L10N_CENTRAL = "https://hg.mozilla.org/l10n-central";
+const PROPERTIES_PATH = "raw-file/default/browser/chrome/browser/activity-stream/newtab.properties";
+const STRINGS_FILE = "strings.properties";
+
+// Get all the locales in l10n-central
+async function getLocales() {
+  console.log(`Getting locales from ${L10N_CENTRAL}`);
+
+  // Add sub repository locales that mozilla-central builds
+  const locales = [];
+  const unbuilt = [];
+  const subrepos = await (await fetch(`${L10N_CENTRAL}?style=json`)).json();
+  subrepos.entries.forEach(({name}) => {
+    if (CENTRAL_LOCALES.includes(name)) {
+      locales.push(name);
+    } else {
+      unbuilt.push(name);
+    }
+  });
+
+  console.log(`Got ${locales.length} mozilla-central locales: ${locales}`);
+  console.log(`Skipped ${unbuilt.length} unbuilt locales: ${unbuilt}`);
+
+  return locales;
+}
+
+// Save the properties file to the locale's directory
+async function saveProperties(locale) {
+  // Only save a file if the repository has the file
+  const url = `${L10N_CENTRAL}/${locale}/${PROPERTIES_PATH}`;
+  const response = await fetch(url);
+  if (!response.ok) {
+    // Indicate that this locale didn't save
+    return locale;
+  }
+
+  // Save the file to the right place
+  const text = await response.text();
+  mkdir(locale);
+  cd(locale);
+  ShellString(text).to(STRINGS_FILE);
+  cd("..");
+
+  // Indicate that we were successful in saving
+  return "";
+}
+
+// Replace and update each locale's strings
+async function updateLocales() {
+  console.log("Switching to and deleting existing l10n tree under: locales");
+
+  cd("locales");
+  ls().forEach(dir => {
+    // Keep the default/source locale as it might have newer strings
+    if (dir !== DEFAULT_LOCALE) {
+      rm("-r", dir);
+    }
+  });
+
+  // Save the properties file for each locale one at a time to avoid too many
+  // parallel connections (resulting in ECONNRESET / socket hang up)
+  const missing = [];
+  for (const locale of await getLocales()) {
+    process.stdout.write(`${locale} `);
+    if (await saveProperties(locale)) {
+      missing.push(locale);
+    }
+  }
+
+  console.log("");
+  console.log(`Skipped ${missing.length} locales without strings: ${missing.sort()}`);
+
+  console.log(`
+Please check the diffs, add/remove files, and then commit the result. Suggested commit message:
+chore(l10n): Update from l10n-central ${new Date()}`);
+}
+
+updateLocales().catch(console.error);
rename from browser/extensions/activity-stream/bin/test-merges.js
rename to browser/components/newtab/bin/test-merges.js
rename from browser/extensions/activity-stream/bin/update-version.js
rename to browser/components/newtab/bin/update-version.js
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/common/Actions.jsm
@@ -0,0 +1,398 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+this.MAIN_MESSAGE_TYPE = "ActivityStream:Main";
+this.CONTENT_MESSAGE_TYPE = "ActivityStream:Content";
+this.PRELOAD_MESSAGE_TYPE = "ActivityStream:PreloadedBrowser";
+this.UI_CODE = 1;
+this.BACKGROUND_PROCESS = 2;
+
+/**
+ * globalImportContext - Are we in UI code (i.e. react, a dom) or some kind of background process?
+ *                       Use this in action creators if you need different logic
+ *                       for ui/background processes.
+ */
+const globalImportContext = typeof Window === "undefined" ? BACKGROUND_PROCESS : UI_CODE;
+// Export for tests
+this.globalImportContext = globalImportContext;
+
+// Create an object that avoids accidental differing key/value pairs:
+// {
+//   INIT: "INIT",
+//   UNINIT: "UNINIT"
+// }
+const actionTypes = {};
+for (const type of [
+  "ADDONS_INFO_REQUEST",
+  "ADDONS_INFO_RESPONSE",
+  "ARCHIVE_FROM_POCKET",
+  "AS_ROUTER_TELEMETRY_USER_EVENT",
+  "BLOCK_URL",
+  "BOOKMARK_URL",
+  "COPY_DOWNLOAD_LINK",
+  "DELETE_BOOKMARK_BY_ID",
+  "DELETE_FROM_POCKET",
+  "DELETE_HISTORY_URL",
+  "DIALOG_CANCEL",
+  "DIALOG_OPEN",
+  "DISABLE_ONBOARDING",
+  "DOWNLOAD_CHANGED",
+  "INIT",
+  "MIGRATION_CANCEL",
+  "MIGRATION_COMPLETED",
+  "MIGRATION_START",
+  "NEW_TAB_INIT",
+  "NEW_TAB_INITIAL_STATE",
+  "NEW_TAB_LOAD",
+  "NEW_TAB_REHYDRATED",
+  "NEW_TAB_STATE_REQUEST",
+  "NEW_TAB_UNLOAD",
+  "OPEN_DOWNLOAD_FILE",
+  "OPEN_LINK",
+  "OPEN_NEW_WINDOW",
+  "OPEN_PRIVATE_WINDOW",
+  "OPEN_WEBEXT_SETTINGS",
+  "PAGE_PRERENDERED",
+  "PLACES_BOOKMARK_ADDED",
+  "PLACES_BOOKMARK_REMOVED",
+  "PLACES_HISTORY_CLEARED",
+  "PLACES_LINKS_CHANGED",
+  "PLACES_LINK_BLOCKED",
+  "PLACES_LINK_DELETED",
+  "PLACES_SAVED_TO_POCKET",
+  "PREFS_INITIAL_VALUES",
+  "PREF_CHANGED",
+  "PREVIEW_REQUEST",
+  "PREVIEW_REQUEST_CANCEL",
+  "PREVIEW_RESPONSE",
+  "REMOVE_DOWNLOAD_FILE",
+  "RICH_ICON_MISSING",
+  "SAVE_SESSION_PERF_DATA",
+  "SAVE_TO_POCKET",
+  "SCREENSHOT_UPDATED",
+  "SECTION_DEREGISTER",
+  "SECTION_DISABLE",
+  "SECTION_ENABLE",
+  "SECTION_MOVE",
+  "SECTION_OPTIONS_CHANGED",
+  "SECTION_REGISTER",
+  "SECTION_UPDATE",
+  "SECTION_UPDATE_CARD",
+  "SETTINGS_CLOSE",
+  "SETTINGS_OPEN",
+  "SET_PREF",
+  "SHOW_DOWNLOAD_FILE",
+  "SHOW_FIREFOX_ACCOUNTS",
+  "SKIPPED_SIGNIN",
+  "SNIPPETS_BLOCKLIST_CLEARED",
+  "SNIPPETS_BLOCKLIST_UPDATED",
+  "SNIPPETS_DATA",
+  "SNIPPETS_RESET",
+  "SNIPPET_BLOCKED",
+  "SUBMIT_EMAIL",
+  "SYSTEM_TICK",
+  "TELEMETRY_IMPRESSION_STATS",
+  "TELEMETRY_PERFORMANCE_EVENT",
+  "TELEMETRY_UNDESIRED_EVENT",
+  "TELEMETRY_USER_EVENT",
+  "TOP_SITES_CANCEL_EDIT",
+  "TOP_SITES_EDIT",
+  "TOP_SITES_INSERT",
+  "TOP_SITES_PIN",
+  "TOP_SITES_PREFS_UPDATED",
+  "TOP_SITES_UNPIN",
+  "TOP_SITES_UPDATED",
+  "TOTAL_BOOKMARKS_REQUEST",
+  "TOTAL_BOOKMARKS_RESPONSE",
+  "UNINIT",
+  "UPDATE_SECTION_PREFS",
+  "WEBEXT_CLICK",
+  "WEBEXT_DISMISS"
+]) {
+  actionTypes[type] = type;
+}
+
+// These are acceptable actions for AS Router messages to have. They can show up
+// as call-to-action buttons in snippets, onboarding tour, etc.
+const ASRouterActions = {};
+for (const type of [
+  "OPEN_PRIVATE_BROWSER_WINDOW",
+  "OPEN_URL",
+  "OPEN_ABOUT_PAGE"
+]) {
+  ASRouterActions[type] = type;
+}
+
+// Helper function for creating routed actions between content and main
+// Not intended to be used by consumers
+function _RouteMessage(action, options) {
+  const meta = action.meta ? {...action.meta} : {};
+  if (!options || !options.from || !options.to) {
+    throw new Error("Routed Messages must have options as the second parameter, and must at least include a .from and .to property.");
+  }
+  // For each of these fields, if they are passed as an option,
+  // add them to the action. If they are not defined, remove them.
+  ["from", "to", "toTarget", "fromTarget", "skipMain", "skipLocal"].forEach(o => {
+    if (typeof options[o] !== "undefined") {
+      meta[o] = options[o];
+    } else if (meta[o]) {
+      delete meta[o];
+    }
+  });
+  return {...action, meta};
+}
+
+/**
+ * AlsoToMain - Creates a message that will be dispatched locally and also sent to the Main process.
+ *
+ * @param  {object} action Any redux action (required)
+ * @param  {object} options
+ * @param  {bool}   skipLocal Used by OnlyToMain to skip the main reducer
+ * @param  {string} fromTarget The id of the content port from which the action originated. (optional)
+ * @return {object} An action with added .meta properties
+ */
+function AlsoToMain(action, fromTarget, skipLocal) {
+  return _RouteMessage(action, {
+    from: CONTENT_MESSAGE_TYPE,
+    to: MAIN_MESSAGE_TYPE,
+    fromTarget,
+    skipLocal
+  });
+}
+
+/**
+ * OnlyToMain - Creates a message that will be sent to the Main process and skip the local reducer.
+ *
+ * @param  {object} action Any redux action (required)
+ * @param  {object} options
+ * @param  {string} fromTarget The id of the content port from which the action originated. (optional)
+ * @return {object} An action with added .meta properties
+ */
+function OnlyToMain(action, fromTarget) {
+  return AlsoToMain(action, fromTarget, true);
+}
+
+/**
+ * BroadcastToContent - Creates a message that will be dispatched to main and sent to ALL content processes.
+ *
+ * @param  {object} action Any redux action (required)
+ * @return {object} An action with added .meta properties
+ */
+function BroadcastToContent(action) {
+  return _RouteMessage(action, {
+    from: MAIN_MESSAGE_TYPE,
+    to: CONTENT_MESSAGE_TYPE
+  });
+}
+
+/**
+ * AlsoToOneContent - Creates a message that will be will be dispatched to the main store
+ *                    and also sent to a particular Content process.
+ *
+ * @param  {object} action Any redux action (required)
+ * @param  {string} target The id of a content port
+ * @param  {bool} skipMain Used by OnlyToOneContent to skip the main process
+ * @return {object} An action with added .meta properties
+ */
+function AlsoToOneContent(action, target, skipMain) {
+  if (!target) {
+    throw new Error("You must provide a target ID as the second parameter of AlsoToOneContent. If you want to send to all content processes, use BroadcastToContent");
+  }
+  return _RouteMessage(action, {
+    from: MAIN_MESSAGE_TYPE,
+    to: CONTENT_MESSAGE_TYPE,
+    toTarget: target,
+    skipMain
+  });
+}
+
+/**
+ * OnlyToOneContent - Creates a message that will be sent to a particular Content process
+ *                    and skip the main reducer.
+ *
+ * @param  {object} action Any redux action (required)
+ * @param  {string} target The id of a content port
+ * @return {object} An action with added .meta properties
+ */
+function OnlyToOneContent(action, target) {
+  return AlsoToOneContent(action, target, true);
+}
+
+/**
+ * AlsoToPreloaded - Creates a message that dispatched to the main reducer and also sent to the preloaded tab.
+ *
+ * @param  {object} action Any redux action (required)
+ * @return {object} An action with added .meta properties
+ */
+function AlsoToPreloaded(action) {
+  return _RouteMessage(action, {
+    from: MAIN_MESSAGE_TYPE,
+    to: PRELOAD_MESSAGE_TYPE
+  });
+}
+
+/**
+ * UserEvent - A telemetry ping indicating a user action. This should only
+ *                   be sent from the UI during a user session.
+ *
+ * @param  {object} data Fields to include in the ping (source, etc.)
+ * @return {object} An AlsoToMain action
+ */
+function UserEvent(data) {
+  return AlsoToMain({
+    type: actionTypes.TELEMETRY_USER_EVENT,
+    data
+  });
+}
+
+/**
+ * ASRouterUserEvent - A telemetry ping indicating a user action from AS router. This should only
+ *                     be sent from the UI during a user session.
+ *
+ * @param  {object} data Fields to include in the ping (source, etc.)
+ * @return {object} An AlsoToMain action
+ */
+function ASRouterUserEvent(data) {
+  return AlsoToMain({
+    type: actionTypes.AS_ROUTER_TELEMETRY_USER_EVENT,
+    data
+  });
+}
+
+/**
+ * UndesiredEvent - A telemetry ping indicating an undesired state.
+ *
+ * @param  {object} data Fields to include in the ping (value, etc.)
+ * @param  {int} importContext (For testing) Override the import context for testing.
+ * @return {object} An action. For UI code, a AlsoToMain action.
+ */
+function UndesiredEvent(data, importContext = globalImportContext) {
+  const action = {
+    type: actionTypes.TELEMETRY_UNDESIRED_EVENT,
+    data
+  };
+  return importContext === UI_CODE ? AlsoToMain(action) : action;
+}
+
+/**
+ * PerfEvent - A telemetry ping indicating a performance-related event.
+ *
+ * @param  {object} data Fields to include in the ping (value, etc.)
+ * @param  {int} importContext (For testing) Override the import context for testing.
+ * @return {object} An action. For UI code, a AlsoToMain action.
+ */
+function PerfEvent(data, importContext = globalImportContext) {
+  const action = {
+    type: actionTypes.TELEMETRY_PERFORMANCE_EVENT,
+    data
+  };
+  return importContext === UI_CODE ? AlsoToMain(action) : action;
+}
+
+/**
+ * ImpressionStats - A telemetry ping indicating an impression stats.
+ *
+ * @param  {object} data Fields to include in the ping
+ * @param  {int} importContext (For testing) Override the import context for testing.
+ * #return {object} An action. For UI code, a AlsoToMain action.
+ */
+function ImpressionStats(data, importContext = globalImportContext) {
+  const action = {
+    type: actionTypes.TELEMETRY_IMPRESSION_STATS,
+    data
+  };
+  return importContext === UI_CODE ? AlsoToMain(action) : action;
+}
+
+function SetPref(name, value, importContext = globalImportContext) {
+  const action = {type: actionTypes.SET_PREF, data: {name, value}};
+  return importContext === UI_CODE ? AlsoToMain(action) : action;
+}
+
+function WebExtEvent(type, data, importContext = globalImportContext) {
+  if (!data || !data.source) {
+    throw new Error("WebExtEvent actions should include a property \"source\", the id of the webextension that should receive the event.");
+  }
+  const action = {type, data};
+  return importContext === UI_CODE ? AlsoToMain(action) : action;
+}
+
+this.actionTypes = actionTypes;
+this.ASRouterActions = ASRouterActions;
+
+this.actionCreators = {
+  BroadcastToContent,
+  UserEvent,
+  ASRouterUserEvent,
+  UndesiredEvent,
+  PerfEvent,
+  ImpressionStats,
+  AlsoToOneContent,
+  OnlyToOneContent,
+  AlsoToMain,
+  OnlyToMain,
+  AlsoToPreloaded,
+  SetPref,
+  WebExtEvent
+};
+
+// These are helpers to test for certain kinds of actions
+this.actionUtils = {
+  isSendToMain(action) {
+    if (!action.meta) {
+      return false;
+    }
+    return action.meta.to === MAIN_MESSAGE_TYPE && action.meta.from === CONTENT_MESSAGE_TYPE;
+  },
+  isBroadcastToContent(action) {
+    if (!action.meta) {
+      return false;
+    }
+    if (action.meta.to === CONTENT_MESSAGE_TYPE && !action.meta.toTarget) {
+      return true;
+    }
+    return false;
+  },
+  isSendToOneContent(action) {
+    if (!action.meta) {
+      return false;
+    }
+    if (action.meta.to === CONTENT_MESSAGE_TYPE && action.meta.toTarget) {
+      return true;
+    }
+    return false;
+  },
+  isSendToPreloaded(action) {
+    if (!action.meta) {
+      return false;
+    }
+    return action.meta.to === PRELOAD_MESSAGE_TYPE &&
+      action.meta.from === MAIN_MESSAGE_TYPE;
+  },
+  isFromMain(action) {
+    if (!action.meta) {
+      return false;
+    }
+    return action.meta.from === MAIN_MESSAGE_TYPE &&
+      action.meta.to === CONTENT_MESSAGE_TYPE;
+  },
+  getPortIdOfSender(action) {
+    return (action.meta && action.meta.fromTarget) || null;
+  },
+  _RouteMessage
+};
+
+const EXPORTED_SYMBOLS = [
+  "actionTypes",
+  "actionCreators",
+  "actionUtils",
+  "ASRouterActions",
+  "globalImportContext",
+  "UI_CODE",
+  "BACKGROUND_PROCESS",
+  "MAIN_MESSAGE_TYPE",
+  "CONTENT_MESSAGE_TYPE",
+  "PRELOAD_MESSAGE_TYPE"
+];
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/common/Dedupe.jsm
@@ -0,0 +1,34 @@
+this.Dedupe = class Dedupe {
+  constructor(createKey) {
+    this.createKey = createKey || this.defaultCreateKey;
+  }
+
+  defaultCreateKey(item) {
+    return item;
+  }
+
+  /**
+   * Dedupe any number of grouped elements favoring those from earlier groups.
+   *
+   * @param {Array} groups Contains an arbitrary number of arrays of elements.
+   * @returns {Array} A matching array of each provided group deduped.
+   */
+  group(...groups) {
+    const globalKeys = new Set();
+    const result = [];
+    for (const values of groups) {
+      const valueMap = new Map();
+      for (const value of values) {
+        const key = this.createKey(value);
+        if (!globalKeys.has(key) && !valueMap.has(key)) {
+          valueMap.set(key, value);
+        }
+      }
+      result.push(valueMap);
+      valueMap.forEach((value, key) => globalKeys.add(key));
+    }
+    return result.map(m => Array.from(m.values()));
+  }
+};
+
+const EXPORTED_SYMBOLS = ["Dedupe"];
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/common/PerfService.jsm
@@ -0,0 +1,125 @@
+/* globals Services */
+"use strict";
+
+/* istanbul ignore if */
+if (typeof ChromeUtils !== "undefined") {
+  ChromeUtils.import("resource://gre/modules/Services.jsm");
+}
+
+let usablePerfObj;
+
+/* istanbul ignore if */
+/* istanbul ignore else */
+if (typeof Services !== "undefined") {
+  // Borrow the high-resolution timer from the hidden window....
+  usablePerfObj = Services.appShell.hiddenDOMWindow.performance;
+} else if (typeof performance !== "undefined") {
+  // we must be running in content space
+  // eslint-disable-next-line no-undef
+  usablePerfObj = performance;
+} else {
+  // This is a dummy object so this file doesn't crash in the node prerendering
+  // task.
+  usablePerfObj = {
+    now() {},
+    mark() {}
+  };
+}
+
+function _PerfService(options) {
+  // For testing, so that we can use a fake Window.performance object with
+  // known state.
+  if (options && options.performanceObj) {
+    this._perf = options.performanceObj;
+  } else {
+    this._perf = usablePerfObj;
+  }
+}
+
+_PerfService.prototype = {
+  /**
+   * Calls the underlying mark() method on the appropriate Window.performance
+   * object to add a mark with the given name to the appropriate performance
+   * timeline.
+   *
+   * @param  {String} name  the name to give the current mark
+   * @return {void}
+   */
+  mark: function mark(str) {
+    this._perf.mark(str);
+  },
+
+  /**
+   * Calls the underlying getEntriesByName on the appropriate Window.performance
+   * object.
+   *
+   * @param  {String} name
+   * @param  {String} type eg "mark"
+   * @return {Array}       Performance* objects
+   */
+  getEntriesByName: function getEntriesByName(name, type) {
+    return this._perf.getEntriesByName(name, type);
+  },
+
+  /**
+   * The timeOrigin property from the appropriate performance object.
+   * Used to ensure that timestamps from the add-on code and the content code
+   * are comparable.
+   *
+   * @note If this is called from a context without a window
+   * (eg a JSM in chrome), it will return the timeOrigin of the XUL hidden
+   * window, which appears to be the first created window (and thus
+   * timeOrigin) in the browser.  Note also, however, there is also a private
+   * hidden window, presumably for private browsing, which appears to be
+   * created dynamically later.  Exactly how/when that shows up needs to be
+   * investigated.
+   *
+   * @return {Number} A double of milliseconds with a precision of 0.5us.
+   */
+  get timeOrigin() {
+    return this._perf.timeOrigin;
+  },
+
+  /**
+   * Returns the "absolute" version of performance.now(), i.e. one that
+   * should ([bug 1401406](https://bugzilla.mozilla.org/show_bug.cgi?id=1401406)
+   * be comparable across both chrome and content.
+   *
+   * @return {Number}
+   */
+  absNow: function absNow() {
+    return this.timeOrigin + this._perf.now();
+  },
+
+  /**
+   * This returns the absolute startTime from the most recent performance.mark()
+   * with the given name.
+   *
+   * @param  {String} name  the name to lookup the start time for
+   *
+   * @return {Number}       the returned start time, as a DOMHighResTimeStamp
+   *
+   * @throws {Error}        "No Marks with the name ..." if none are available
+   *
+   * @note Always surround calls to this by try/catch.  Otherwise your code
+   * may fail when the `privacy.resistFingerprinting` pref is true.  When
+   * this pref is set, all attempts to get marks will likely fail, which will
+   * cause this method to throw.
+   *
+   * See [bug 1369303](https://bugzilla.mozilla.org/show_bug.cgi?id=1369303)
+   * for more info.
+   */
+  getMostRecentAbsMarkStartByName(name) {
+    let entries = this.getEntriesByName(name, "mark");
+
+    if (!entries.length) {
+      throw new Error(`No marks with the name ${name}`);
+    }
+
+    let mostRecentEntry = entries[entries.length - 1];
+    return this._perf.timeOrigin + mostRecentEntry.startTime;
+  }
+};
+
+this.perfService = new _PerfService();
+const EXPORTED_SYMBOLS = ["_PerfService", "perfService"];
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/common/PrerenderData.jsm
@@ -0,0 +1,105 @@
+class _PrerenderData {
+  constructor(options) {
+    this.initialPrefs = options.initialPrefs;
+    this.initialSections = options.initialSections;
+    this._setValidation(options.validation);
+  }
+
+  get validation() {
+    return this._validation;
+  }
+
+  set validation(value) {
+    this._setValidation(value);
+  }
+
+  get invalidatingPrefs() {
+    return this._invalidatingPrefs;
+  }
+
+    // This is needed so we can use it in the constructor
+  _setValidation(value = []) {
+    this._validation = value;
+    this._invalidatingPrefs = value.reduce((result, next) => {
+      if (typeof next === "string") {
+        result.push(next);
+        return result;
+      } else if (next && next.oneOf) {
+        return result.concat(next.oneOf);
+      } else if (next && next.indexedDB) {
+        return result.concat(next.indexedDB);
+      }
+      throw new Error("Your validation configuration is not properly configured");
+    }, []);
+  }
+
+  arePrefsValid(getPref, indexedDBPrefs) {
+    for (const prefs of this.validation) {
+      // {oneOf: ["foo", "bar"]}
+      if (prefs && prefs.oneOf && !prefs.oneOf.some(name => getPref(name) === this.initialPrefs[name])) {
+        return false;
+
+        // {indexedDB: ["foo", "bar"]}
+      } else if (indexedDBPrefs && prefs && prefs.indexedDB) {
+        const anyModifiedPrefs = prefs.indexedDB.some(prefName => indexedDBPrefs.some(pref => pref && pref[prefName]));
+        if (anyModifiedPrefs) {
+          return false;
+        }
+        // "foo"
+      } else if (getPref(prefs) !== this.initialPrefs[prefs]) {
+        return false;
+      }
+    }
+    return true;
+  }
+}
+
+this.PrerenderData = new _PrerenderData({
+  initialPrefs: {
+    "migrationExpired": true,
+    "feeds.topsites": true,
+    "showSearch": true,
+    "topSitesRows": 1,
+    "feeds.section.topstories": true,
+    "feeds.section.highlights": true,
+    "sectionOrder": "topsites,topstories,highlights",
+    "collapsed": false
+  },
+  // Prefs listed as invalidating will prevent the prerendered version
+  // of AS from being used if their value is something other than what is listed
+  // here. This is required because some preferences cause the page layout to be
+  // too different for the prerendered version to be used. Unfortunately, this
+  // will result in users who have modified some of their preferences not being
+  // able to get the benefits of prerendering.
+  validation: [
+    "feeds.topsites",
+    "showSearch",
+    "topSitesRows",
+    "sectionOrder",
+    // This means if either of these are set to their default values,
+    // prerendering can be used.
+    {oneOf: ["feeds.section.topstories", "feeds.section.highlights"]},
+    // If any component has the following preference set to `true` it will
+    // invalidate the prerendered version.
+    {indexedDB: ["collapsed"]}
+  ],
+  initialSections: [
+    {
+      enabled: true,
+      icon: "pocket",
+      id: "topstories",
+      order: 1,
+      title: {id: "header_recommended_by", values: {provider: "Pocket"}}
+    },
+    {
+      enabled: true,
+      id: "highlights",
+      icon: "highlights",
+      order: 2,
+      title: {id: "header_highlights"}
+    }
+  ]
+});
+
+this._PrerenderData = _PrerenderData;
+const EXPORTED_SYMBOLS = ["PrerenderData", "_PrerenderData"];
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/common/Reducers.jsm
@@ -0,0 +1,380 @@
+/* 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 {actionTypes: at} = ChromeUtils.import("resource://activity-stream/common/Actions.jsm", {});
+const {Dedupe} = ChromeUtils.import("resource://activity-stream/common/Dedupe.jsm", {});
+
+const TOP_SITES_DEFAULT_ROWS = 1;
+const TOP_SITES_MAX_SITES_PER_ROW = 8;
+
+const dedupe = new Dedupe(site => site && site.url);
+
+const INITIAL_STATE = {
+  App: {
+    // Have we received real data from the app yet?
+    initialized: false
+  },
+  Snippets: {initialized: false},
+  TopSites: {
+    // Have we received real data from history yet?
+    initialized: false,
+    // The history (and possibly default) links
+    rows: [],
+    // Used in content only to dispatch action to TopSiteForm.
+    editForm: null
+  },
+  Prefs: {
+    initialized: false,
+    values: {}
+  },
+  Dialog: {
+    visible: false,
+    data: {}
+  },
+  Sections: []
+};
+
+function App(prevState = INITIAL_STATE.App, action) {
+  switch (action.type) {
+    case at.INIT:
+      return Object.assign({}, prevState, action.data || {}, {initialized: true});
+    default:
+      return prevState;
+  }
+}
+
+/**
+ * insertPinned - Inserts pinned links in their specified slots
+ *
+ * @param {array} a list of links
+ * @param {array} a list of pinned links
+ * @return {array} resulting list of links with pinned links inserted
+ */
+function insertPinned(links, pinned) {
+  // Remove any pinned links
+  const pinnedUrls = pinned.map(link => link && link.url);
+  let newLinks = links.filter(link => (link ? !pinnedUrls.includes(link.url) : false));
+  newLinks = newLinks.map(link => {
+    if (link && link.isPinned) {
+      delete link.isPinned;
+      delete link.pinIndex;
+    }
+    return link;
+  });
+
+  // Then insert them in their specified location
+  pinned.forEach((val, index) => {
+    if (!val) { return; }
+    let link = Object.assign({}, val, {isPinned: true, pinIndex: index});
+    if (index > newLinks.length) {
+      newLinks[index] = link;
+    } else {
+      newLinks.splice(index, 0, link);
+    }
+  });
+
+  return newLinks;
+}
+
+function TopSites(prevState = INITIAL_STATE.TopSites, action) {
+  let hasMatch;
+  let newRows;
+  switch (action.type) {
+    case at.TOP_SITES_UPDATED:
+      if (!action.data || !action.data.links) {
+        return prevState;
+      }
+      return Object.assign({}, prevState, {initialized: true, rows: action.data.links}, action.data.pref ? {pref: action.data.pref} : {});
+    case at.TOP_SITES_PREFS_UPDATED:
+      return Object.assign({}, prevState, {pref: action.data.pref});
+    case at.TOP_SITES_EDIT:
+      return Object.assign({}, prevState, {
+        editForm: {
+          index: action.data.index,
+          previewResponse: null
+        }
+      });
+    case at.TOP_SITES_CANCEL_EDIT:
+      return Object.assign({}, prevState, {editForm: null});
+    case at.PREVIEW_RESPONSE:
+      if (!prevState.editForm || action.data.url !== prevState.editForm.previewUrl) {
+        return prevState;
+      }
+      return Object.assign({}, prevState, {
+        editForm: {
+          index: prevState.editForm.index,
+          previewResponse: action.data.preview,
+          previewUrl: action.data.url
+        }
+      });
+    case at.PREVIEW_REQUEST:
+      if (!prevState.editForm) {
+        return prevState;
+      }
+      return Object.assign({}, prevState, {
+        editForm: {
+          index: prevState.editForm.index,
+          previewResponse: null,
+          previewUrl: action.data.url
+        }
+      });
+    case at.PREVIEW_REQUEST_CANCEL:
+      if (!prevState.editForm) {
+        return prevState;
+      }
+      return Object.assign({}, prevState, {
+        editForm: {
+          index: prevState.editForm.index,
+          previewResponse: null
+        }
+      });
+    case at.SCREENSHOT_UPDATED:
+      newRows = prevState.rows.map(row => {
+        if (row && row.url === action.data.url) {
+          hasMatch = true;
+          return Object.assign({}, row, {screenshot: action.data.screenshot});
+        }
+        return row;
+      });
+      return hasMatch ? Object.assign({}, prevState, {rows: newRows}) : prevState;
+    case at.PLACES_BOOKMARK_ADDED:
+      if (!action.data) {
+        return prevState;
+      }
+      newRows = prevState.rows.map(site => {
+        if (site && site.url === action.data.url) {
+          const {bookmarkGuid, bookmarkTitle, dateAdded} = action.data;
+          return Object.assign({}, site, {bookmarkGuid, bookmarkTitle, bookmarkDateCreated: dateAdded});
+        }
+        return site;
+      });
+      return Object.assign({}, prevState, {rows: newRows});
+    case at.PLACES_BOOKMARK_REMOVED:
+      if (!action.data) {
+        return prevState;
+      }
+      newRows = prevState.rows.map(site => {
+        if (site && site.url === action.data.url) {
+          const newSite = Object.assign({}, site);
+          delete newSite.bookmarkGuid;
+          delete newSite.bookmarkTitle;
+          delete newSite.bookmarkDateCreated;
+          return newSite;
+        }
+        return site;
+      });
+      return Object.assign({}, prevState, {rows: newRows});
+    case at.PLACES_LINK_DELETED:
+      if (!action.data) {
+        return prevState;
+      }
+      newRows = prevState.rows.filter(site => action.data.url !== site.url);
+      return Object.assign({}, prevState, {rows: newRows});
+    default:
+      return prevState;
+  }
+}
+
+function Dialog(prevState = INITIAL_STATE.Dialog, action) {
+  switch (action.type) {
+    case at.DIALOG_OPEN:
+      return Object.assign({}, prevState, {visible: true, data: action.data});
+    case at.DIALOG_CANCEL:
+      return Object.assign({}, prevState, {visible: false});
+    case at.DELETE_HISTORY_URL:
+      return Object.assign({}, INITIAL_STATE.Dialog);
+    default:
+      return prevState;
+  }
+}
+
+function Prefs(prevState = INITIAL_STATE.Prefs, action) {
+  let newValues;
+  switch (action.type) {
+    case at.PREFS_INITIAL_VALUES:
+      return Object.assign({}, prevState, {initialized: true, values: action.data});
+    case at.PREF_CHANGED:
+      newValues = Object.assign({}, prevState.values);
+      newValues[action.data.name] = action.data.value;
+      return Object.assign({}, prevState, {values: newValues});
+    default:
+      return prevState;
+  }
+}
+
+function Sections(prevState = INITIAL_STATE.Sections, action) {
+  let hasMatch;
+  let newState;
+  switch (action.type) {
+    case at.SECTION_DEREGISTER:
+      return prevState.filter(section => section.id !== action.data);
+    case at.SECTION_REGISTER:
+      // If section exists in prevState, update it
+      newState = prevState.map(section => {
+        if (section && section.id === action.data.id) {
+          hasMatch = true;
+          return Object.assign({}, section, action.data);
+        }
+        return section;
+      });
+      // Otherwise, append it
+      if (!hasMatch) {
+        const initialized = !!(action.data.rows && action.data.rows.length > 0);
+        const section = Object.assign({title: "", rows: [], enabled: false}, action.data, {initialized});
+        newState.push(section);
+      }
+      return newState;
+    case at.SECTION_UPDATE:
+      newState = prevState.map(section => {
+        if (section && section.id === action.data.id) {
+          // If the action is updating rows, we should consider initialized to be true.
+          // This can be overridden if initialized is defined in the action.data
+          const initialized = action.data.rows ? {initialized: true} : {};
+
+          // Make sure pinned cards stay at their current position when rows are updated.
+          // Disabling a section (SECTION_UPDATE with empty rows) does not retain pinned cards.
+          if (action.data.rows && action.data.rows.length > 0 && section.rows.find(card => card.pinned)) {
+            const rows = Array.from(action.data.rows);
+            section.rows.forEach((card, index) => {
+              if (card.pinned) {
+                rows.splice(index, 0, card);
+              }
+            });
+            return Object.assign({}, section, initialized, Object.assign({}, action.data, {rows}));
+          }
+
+          return Object.assign({}, section, initialized, action.data);
+        }
+        return section;
+      });
+
+      if (!action.data.dedupeConfigurations) {
+        return newState;
+      }
+
+      action.data.dedupeConfigurations.forEach(dedupeConf => {
+        newState = newState.map(section => {
+          if (section.id === dedupeConf.id) {
+            const dedupedRows = dedupeConf.dedupeFrom.reduce((rows, dedupeSectionId) => {
+              const dedupeSection = newState.find(s => s.id === dedupeSectionId);
+              const [, newRows] = dedupe.group(dedupeSection.rows, rows);
+              return newRows;
+            }, section.rows);
+
+            return Object.assign({}, section, {rows: dedupedRows});
+          }
+
+          return section;
+        });
+      });
+
+      return newState;
+    case at.SECTION_UPDATE_CARD:
+      return prevState.map(section => {
+        if (section && section.id === action.data.id && section.rows) {
+          const newRows = section.rows.map(card => {
+            if (card.url === action.data.url) {
+              return Object.assign({}, card, action.data.options);
+            }
+            return card;
+          });
+          return Object.assign({}, section, {rows: newRows});
+        }
+        return section;
+      });
+    case at.PLACES_BOOKMARK_ADDED:
+      if (!action.data) {
+        return prevState;
+      }
+      return prevState.map(section => Object.assign({}, section, {
+        rows: section.rows.map(item => {
+          // find the item within the rows that is attempted to be bookmarked
+          if (item.url === action.data.url) {
+            const {bookmarkGuid, bookmarkTitle, dateAdded} = action.data;
+            return Object.assign({}, item, {
+              bookmarkGuid,
+              bookmarkTitle,
+              bookmarkDateCreated: dateAdded,
+              type: "bookmark"
+            });
+          }
+          return item;
+        })
+      }));
+    case at.PLACES_SAVED_TO_POCKET:
+      if (!action.data) {
+        return prevState;
+      }
+      return prevState.map(section => Object.assign({}, section, {
+        rows: section.rows.map(item => {
+          if (item.url === action.data.url) {
+            return Object.assign({}, item, {
+              open_url: action.data.open_url,
+              pocket_id: action.data.pocket_id,
+              title: action.data.title,
+              type: "pocket"
+            });
+          }
+          return item;
+        })
+      }));
+    case at.PLACES_BOOKMARK_REMOVED:
+      if (!action.data) {
+        return prevState;
+      }
+      return prevState.map(section => Object.assign({}, section, {
+        rows: section.rows.map(item => {
+          // find the bookmark within the rows that is attempted to be removed
+          if (item.url === action.data.url) {
+            const newSite = Object.assign({}, item);
+            delete newSite.bookmarkGuid;
+            delete newSite.bookmarkTitle;
+            delete newSite.bookmarkDateCreated;
+            if (!newSite.type || newSite.type === "bookmark") {
+              newSite.type = "history";
+            }
+            return newSite;
+          }
+          return item;
+        })
+      }));
+    case at.PLACES_LINK_DELETED:
+    case at.PLACES_LINK_BLOCKED:
+      if (!action.data) {
+        return prevState;
+      }
+      return prevState.map(section =>
+        Object.assign({}, section, {rows: section.rows.filter(site => site.url !== action.data.url)}));
+    case at.DELETE_FROM_POCKET:
+    case at.ARCHIVE_FROM_POCKET:
+      return prevState.map(section =>
+        Object.assign({}, section, {rows: section.rows.filter(site => site.pocket_id !== action.data.pocket_id)}));
+    default:
+      return prevState;
+  }
+}
+
+function Snippets(prevState = INITIAL_STATE.Snippets, action) {
+  switch (action.type) {
+    case at.SNIPPETS_DATA:
+      return Object.assign({}, prevState, {initialized: true}, action.data);
+    case at.SNIPPET_BLOCKED:
+      return Object.assign({}, prevState, {blockList: prevState.blockList.concat(action.data)});
+    case at.SNIPPETS_BLOCKLIST_CLEARED:
+      return Object.assign({}, prevState, {blockList: []});
+    case at.SNIPPETS_RESET:
+      return INITIAL_STATE.Snippets;
+    default:
+      return prevState;
+  }
+}
+
+this.INITIAL_STATE = INITIAL_STATE;
+this.TOP_SITES_DEFAULT_ROWS = TOP_SITES_DEFAULT_ROWS;
+this.TOP_SITES_MAX_SITES_PER_ROW = TOP_SITES_MAX_SITES_PER_ROW;
+
+this.reducers = {TopSites, App, Snippets, Prefs, Dialog, Sections};
+
+const EXPORTED_SYMBOLS = ["reducers", "INITIAL_STATE", "insertPinned", "TOP_SITES_DEFAULT_ROWS", "TOP_SITES_MAX_SITES_PER_ROW"];
rename from browser/extensions/activity-stream/content-src/.eslintrc.js
rename to browser/components/newtab/content-src/.eslintrc.js
rename from browser/extensions/activity-stream/content-src/activity-stream-prerender.jsx
rename to browser/components/newtab/content-src/activity-stream-prerender.jsx
rename from browser/extensions/activity-stream/content-src/activity-stream.jsx
rename to browser/components/newtab/content-src/activity-stream.jsx
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/content-src/asrouter/asrouter-content.jsx
@@ -0,0 +1,274 @@
+import {actionCreators as ac, ASRouterActions as ra} from "common/Actions.jsm";
+import {LocalizationProvider, Localized} from "fluent-react";
+import {OUTGOING_MESSAGE_NAME as AS_GENERAL_OUTGOING_MESSAGE_NAME} from "content-src/lib/init-store";
+import {ImpressionsWrapper} from "./components/ImpressionsWrapper/ImpressionsWrapper";
+import {MessageContext} from "fluent";
+import {OnboardingMessage} from "./templates/OnboardingMessage/OnboardingMessage";
+import React from "react";
+import ReactDOM from "react-dom";
+import {safeURI} from "./template-utils";
+import {SimpleSnippet} from "./templates/SimpleSnippet/SimpleSnippet";
+
+const INCOMING_MESSAGE_NAME = "ASRouter:parent-to-child";
+const OUTGOING_MESSAGE_NAME = "ASRouter:child-to-parent";
+
+export 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) {
+    ASRouterUtils.sendMessage({type: "BLOCK_MESSAGE_BY_ID", data: {id}});
+  },
+  blockBundle(bundle) {
+    ASRouterUtils.sendMessage({type: "BLOCK_BUNDLE", data: {bundle}});
+  },
+  executeAction({button_action, button_action_params}) {
+    if (button_action in ra) {
+      ASRouterUtils.sendMessage({type: button_action, data: {button_action_params}});
+    }
+  },
+  unblockById(id) {
+    ASRouterUtils.sendMessage({type: "UNBLOCK_MESSAGE_BY_ID", data: {id}});
+  },
+  unblockBundle(bundle) {
+    ASRouterUtils.sendMessage({type: "UNBLOCK_BUNDLE", data: {bundle}});
+  },
+  getNextMessage() {
+    ASRouterUtils.sendMessage({type: "GET_NEXT_MESSAGE"});
+  },
+  overrideMessage(id) {
+    ASRouterUtils.sendMessage({type: "OVERRIDE_MESSAGE", data: {id}});
+  },
+  sendTelemetry(ping) {
+    const payload = ac.ASRouterUserEvent(ping);
+    global.RPMSendAsyncMessage(AS_GENERAL_OUTGOING_MESSAGE_NAME, payload);
+  },
+  getEndpoint() {
+    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")
+        };
+      } catch (e) {}
+    }
+
+    return null;
+  }
+};
+
+// 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));
+}
+
+function generateMessages(content) {
+  const cx = new MessageContext("en-US");
+  cx.addMessages(`RichTextSnippet = ${content}`);
+  return [cx];
+}
+
+// Elements allowed in snippet content
+const ALLOWED_TAGS = {
+  b: <b />,
+  i: <i />,
+  u: <u />,
+  strong: <strong />,
+  em: <em />,
+  br: <br />
+};
+
+/**
+ * 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.
+ */
+export function convertLinks(links, sendClick) {
+  if (links) {
+    return Object.keys(links).reduce((acc, linkTag) => {
+      acc[linkTag] = <a href={safeURI(links[linkTag].url)} data-metric={links[linkTag].metric} onClick={sendClick} />;
+      return acc;
+    }, {});
+  }
+
+  return null;
+}
+
+/**
+ * Message wrapper used to sanitize markup and render HTML.
+ */
+function RichText(props) {
+  return (
+    <Localized id="RichTextSnippet" {...ALLOWED_TAGS} {...convertLinks(props.links, props.sendClick)}>
+      <span>{props.text}</span>
+    </Localized>
+  );
+}
+
+export class ASRouterUISurface extends React.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) {
+    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"
+    };
+    this.sendUserActionTelemetry({event: "CLICK_BUTTON", ...metric});
+  }
+
+  onBlockById(id) {
+    return () => ASRouterUtils.blockById(id);
+  }
+
+  clearBundle(bundle) {
+    return () => ASRouterUtils.blockBundle(bundle);
+  }
+
+  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: {}});
+        }
+        break;
+      case "CLEAR_BUNDLE":
+        if (this.state.bundle.bundle) {
+          this.setState({bundle: {}});
+        }
+        break;
+      case "CLEAR_ALL":
+        this.setState({message: {}, bundle: {}});
+    }
+  }
+
+  componentWillMount() {
+    const endpoint = ASRouterUtils.getEndpoint();
+    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: "firstRun"}});
+    } else {
+      ASRouterUtils.sendMessage({type: "CONNECT_UI_REQUEST", data: {endpoint}});
+    }
+  }
+
+  componentWillUnmount() {
+    ASRouterUtils.removeListener(this.onMessageFromParent);
+  }
+
+  renderSnippets() {
+    return (
+      <ImpressionsWrapper
+        id="NEWTAB_FOOTER_BAR"
+        message={this.state.message}
+        sendImpression={this.sendImpression}
+        shouldSendImpressionOnUpdate={shouldSendImpressionOnUpdate}
+        // This helps with testing
+        document={this.props.document}>
+          <LocalizationProvider messages={generateMessages(this.state.message.content.text)}>
+            <SimpleSnippet
+              {...this.state.message}
+              richText={<RichText text={this.state.message.content.text}
+                                  links={this.state.message.content.links}
+                                  sendClick={this.sendClick} />}
+              UISurface="NEWTAB_FOOTER_BAR"
+              getNextMessage={ASRouterUtils.getNextMessage}
+              onBlock={this.onBlockById(this.state.message.id)}
+              sendUserActionTelemetry={this.sendUserActionTelemetry} />
+          </LocalizationProvider>
+      </ImpressionsWrapper>);
+  }
+
+  renderOnboarding() {
+    return (
+      <OnboardingMessage
+        {...this.state.bundle}
+        UISurface="NEWTAB_OVERLAY"
+        onAction={ASRouterUtils.executeAction}
+        onDoneButton={this.clearBundle(this.state.bundle.bundle)}
+        getNextMessage={ASRouterUtils.getNextMessage}
+        sendUserActionTelemetry={this.sendUserActionTelemetry} />);
+  }
+
+  render() {
+    const {message, bundle} = this.state;
+    if (!message.id && !bundle.template) { return null; }
+    if (bundle.template === "onboarding") { return this.renderOnboarding(); }
+    return this.renderSnippets();
+  }
+}
+
+ASRouterUISurface.defaultProps = {document: global.document};
+
+export class ASRouterContent {
+  constructor() {
+    this.initialized = false;
+    this.containerElement = null;
+  }
+
+  _mount() {
+    this.containerElement = global.document.getElementById("snippets-container");
+    ReactDOM.render(<ASRouterUISurface />, this.containerElement);
+  }
+
+  _unmount() {
+    ReactDOM.unmountComponentAtNode(this.containerElement);
+  }
+
+  init() {
+    this._mount();
+    this.initialized = true;
+  }
+
+  uninit() {
+    if (this.initialized) {
+      this._unmount();
+      this.initialized = false;
+    }
+  }
+}
rename from browser/extensions/activity-stream/content-src/asrouter/components/Button/Button.jsx
rename to browser/components/newtab/content-src/asrouter/components/Button/Button.jsx
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/content-src/asrouter/components/Button/_Button.scss
@@ -0,0 +1,14 @@
+.ASRouterButton {
+  white-space: nowrap;
+  border-radius: 4px;
+  border: 1px solid var(--newtab-border-secondary-color);
+  background-color: var(--newtab-button-secondary-color);
+  font-family: inherit;
+  padding: 8px 15px;
+  margin-inline-start: 12px;
+  color: inherit;
+
+  .tall & {
+    margin-inline-start: 20px;
+  }
+}
rename from browser/extensions/activity-stream/content-src/asrouter/components/ImpressionsWrapper/ImpressionsWrapper.jsx
rename to browser/components/newtab/content-src/asrouter/components/ImpressionsWrapper/ImpressionsWrapper.jsx
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/content-src/asrouter/components/ModalOverlay/ModalOverlay.jsx
@@ -0,0 +1,30 @@
+import React from "react";
+
+export class ModalOverlay extends React.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 (
+      <div>
+        <div className={`modalOverlayOuter ${active ? "active" : ""}`} />
+        <div className={`modalOverlayInner ${active ? "active" : ""}`}>
+          <h2> {title} </h2>
+          {this.props.children}
+          <div className="footer">
+            <button tabIndex="2" onClick={this.props.onDoneButton} className="button primary modalButton"> {button_label} </button>
+          </div>
+        </div>
+      </div>
+    );
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/content-src/asrouter/components/ModalOverlay/_ModalOverlay.scss
@@ -0,0 +1,110 @@
+.activity-stream {
+  &.modal-open {
+    overflow: hidden;
+  }
+}
+
+.modalOverlayOuter {
+  background: $white;
+  opacity: 0.93;
+  height: 100%;
+  position: fixed;
+  top: 0;
+  width: 100%;
+  display: none;
+  z-index: 1100;
+
+  &.active {
+    display: block;
+  }
+}
+
+.modalOverlayInner {
+  width: 960px;
+  height: 510px;
+  position: fixed;
+  top: calc(50% - 255px); // halfway down minus half the height of the modal
+  left: calc(50% - 480px); // halfway across minus half the width of the modal
+  background: $white;
+  box-shadow: 0 1px 15px 0 $black-30;
+  border-radius: 4px;
+  display: none;
+  z-index: 1101;
+
+
+  // modal takes over entire screen
+  @media(max-width: 960px) {
+    width: 100%;
+    height: 100%;
+    top: 0;
+    left: 0;
+    box-shadow: none;
+    border-radius: 0;
+  }
+
+  // if modal is short enough, add a vertical scroll bar
+  @media(max-width: 850px) and (max-height: 730px) {
+    overflow-y: scroll;
+  }
+
+  // if modal is narrow enough, add a vertical scroll bar
+  @media(max-width: 650px) and (max-height: 600px) {
+    overflow-y: scroll;
+  }
+
+  &.active {
+    display: block;
+  }
+
+  h2 {
+    color: $grey-60;
+    text-align: center;
+    font-weight: 200;
+    margin-top: 30px;
+    font-size: 28px;
+    line-height: 37px;
+    letter-spacing: -0.13px;
+
+    @media(max-width: 960px) {
+      margin-top: 100px;
+    }
+
+    @media(max-width: 850px) {
+      margin-top: 30px;
+    }
+  }
+
+  .footer {
+    border-top: 1px solid $grey-30;
+    height: 70px;
+    width: 100%;
+    position: absolute;
+    bottom: 0;
+    text-align: center;
+    background-color: $white;
+
+    // if modal is short enough, footer becomes sticky
+    @media(max-width: 850px) and (max-height: 730px) {
+      position: sticky;
+    }
+
+    // if modal is narrow enough, footer becomes sticky
+    @media(max-width: 650px) and (max-height: 600px) {
+      position: sticky;
+    }
+
+    .modalButton {
+      margin-top: 20px;
+      width: 150px;
+      height: 30px;
+      padding: 4px 0 6px;
+      font-size: 15px;
+
+      &:focus,
+      &.active {
+        box-shadow: $shadow-primary;
+        transition: box-shadow 150ms;
+      }
+    }
+  }
+}
rename from browser/extensions/activity-stream/content-src/asrouter/components/SnippetBase/SnippetBase.jsx
rename to browser/components/newtab/content-src/asrouter/components/SnippetBase/SnippetBase.jsx
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/content-src/asrouter/components/SnippetBase/_SnippetBase.scss
@@ -0,0 +1,58 @@
+.SnippetBaseContainer {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  background-color: var(--newtab-snippets-background-color);
+  color: var(--newtab-text-primary-color);
+  font-size: 12px;
+  line-height: 16px;
+  border-top: 1px solid var(--newtab-snippets-hairline-color);
+  box-shadow: $shadow-secondary;
+  display: flex;
+  align-items: center;
+
+  .innerWrapper {
+    margin: 0 auto;
+    display: flex;
+    align-items: center;
+    padding: 12px $section-horizontal-padding;
+
+    // This is to account for the block button on smaller screens
+    padding-inline-end: 36px;
+    @media (min-width: $break-point-large) {
+      padding-inline-end: $section-horizontal-padding;
+    }
+
+    max-width: $wrapper-max-width-large;
+    @media (min-width: $break-point-widest) {
+      max-width: $wrapper-max-width-widest;
+    }
+  }
+
+  .blockButton {
+    display: none;
+    background: none;
+    border: 0;
+    position: absolute;
+    top: 50%;
+    inset-inline-end: 12px;
+    height: 16px;
+    width: 16px;
+    background-image: url('resource://activity-stream/data/content/assets/glyph-dismiss-16.svg');
+    -moz-context-properties: fill;
+    fill: var(--newtab-icon-primary-color);
+    opacity: 0.5;
+    margin-top: -8px;
+    padding: 0;
+    cursor: pointer;
+
+    @media (min-width: 766px) {
+      inset-inline-end: 24px;
+    }
+  }
+
+  &:hover .blockButton {
+    display: block;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/content-src/asrouter/schemas/message-format.md
@@ -0,0 +1,126 @@
+## Activity Stream Router message format
+
+Field name | Type     | Required | Description | Example / Note
+---        | ---      | ---      | ---         | ---
+`id`       | `string` | Yes | A unique identifier for the message that should not conflict with any other previous message | `ONBOARDING_1`
+`template` | `string` | Yes | An id matching an existing Activity Stream Router template | [See example](https://github.com/mozilla/activity-stream/blob/33669c67c2269078a6d3d6d324fb48175d98f634/system-addon/content-src/message-center/templates/SimpleSnippet.jsx)
+`publish_start` | `date` | No | When to start showing the message | `1524474850876`
+`publish_end` | `date` | No | When to stop showing the message | `1524474850876`
+`content` | `object` | Yes | An object containing all variables/props to be rendered in the template. Subset of allowed tags detailed below. | [See example below](#html-subset)
+`campaign` | `string` | No | Campaign id that the message belongs to | `RustWebAssembly`
+`targeting` | `string` `JEXL` | No | A [JEXL expression](http://normandy.readthedocs.io/en/latest/user/filter_expressions.html#jexl-basics) with all targeting information needed in order to decide if the message is shown | Not yet implemented, [Examples](#targeting-attributes)
+`trigger` | `string` | No | An event or condition upon which the message will be immediately shown. This can be combined with `targeting`. Messages that define a trigger will not be shown during non-trigger-based passive message rotation.
+`frequency` | `object` | No | A definition for frequency cap information for the message
+`frequency.lifetime` | `integer` | No | The maximum number of lifetime impressions for the message.
+`frequency.custom` | `array` | No | An array of frequency cap definition objects including `period`, a time period in milliseconds, and `cap`, a max number of impressions for that period.
+
+### Message example
+```javascript
+{
+  id: "ONBOARDING_1",
+  template: "simple_snippet",
+  content: {
+    title: "Find it faster",
+    body: "Access all of your favorite search engines with a click. Search the whole Web or just one website from the search box."
+  },
+  targeting: "hasFxAccount && !addonsInfo.addons['activity-stream@mozilla.org']",
+  frequency: {
+    lifetime: 20,
+    custom: [{period: "daily", cap: 5}, {period: 3600000, cap: 1}]
+  }
+}
+```
+
+### HTML subset
+The following tags are allowed in the content of the snippet: `i, b, u, strong, em, br`.
+
+Links cannot be rendered using regular anchor tags because [Fluent does not allow for href attributes](https://github.com/projectfluent/fluent.js/blob/a03d3aa833660f8c620738b26c80e46b1a4edb05/fluent-dom/src/overlay.js#L13). They will be wrapped in custom tags, for example `<cta>link</cta>` and the url will be provided as part of the payload:
+```
+{
+  "id": "7899",
+  "content": {
+    "text": "Use the CMD (CTRL) + T keyboard shortcut to <cta>open a new tab quickly!</cta>",
+    "links": {
+      "cta": {
+        "url": "https://support.mozilla.org/en-US/kb/keyboard-shortcuts-perform-firefox-tasks-quickly"
+      }
+    }
+  }
+}
+```
+If a tag that is not on the allowed is used, the text content will be extracted and displayed.
+
+Grouping multiple allowed elements is not possible, only the first level will be used: `<u><b>text</b></u>` will be interpreted as `<u>text</u>`.
+
+### Targeting attributes
+For a more in-depth explanation of JEXL syntax you can read the [Normady project docs](https://normandy.readthedocs.io/en/stable/user/filters.html#jexl-basics).
+
+Currently we expose the following targeting attributes that can be used by messages:
+
+Name | Type | Example value | Description
+---  | ---  | ---           | ---
+`addonsInfo` | `Object` | [example below](#addonsinfo-example) | Information about the addons the user has installed
+`devToolsOpenedCount` | `Integer` | Number of usages of the web console or scratchpad
+`hasFxAccount` | `Boolean` | `true` | Does the user have a firefox account
+`isDefaultBrowser` | `Boolean` or `null` | Is Firefox the user's default browser? If we could not determine the default browser, this value is `null`
+`profileAgeCreated` | Number | `1522843725924` | Profile creation timestamp
+`profileAgeReset` | `Number` or `undefined` | `1522843725924` | When (if) the profile was reset
+`searchEngines` | `Object` | [example below](#searchengines-example) | Information about the current and available search engines
+
+#### addonsInfo Example
+
+```javascript
+{
+  "addons": {
+    ...
+    "activity-stream@mozilla.org": {
+      "version": "2018.07.06.1113-783442c0",
+      "type": "extension",
+      "isSystem": true,
+      "isWebExtension": false,
+      "name": "Activity Stream",
+      "userDisabled": false,
+      "installDate": "2018-03-10T03:41:06.000Z"
+    }
+  },
+  "isFullData": true
+}
+```
+
+#### searchEngines Example
+
+```javascript
+{
+  "searchEngines": {
+    "current": "google",
+    "installed": ["google", "amazondotcom", "duckduckgo"]
+  }
+}
+```
+
+#### Usage
+A message needs to contain the `targeting` property (JEXL string) which is evaluated against the provided attributes.
+Examples:
+
+```javascript
+{
+  "id": "7864",
+  "content": {...},
+  // simple equality check
+  "targeting": "hasFxAccount == true"
+}
+
+{
+  "id": "7865",
+  "content": {...},
+  // using JEXL transforms and combining two attributes
+  "targeting": "hasFxAccount == true && profileAgeCreated > '2018-01-07'|date"
+}
+
+{
+  "id": "7866",
+  "content": {...},
+  // targeting addon information
+  "targeting": "addonsInfo.addons['activity-stream@mozilla.org'].name == 'Activity Stream'"
+}
+```
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/content-src/asrouter/schemas/provider-response.schema.json
@@ -0,0 +1,85 @@
+{
+  "title": "ProviderResponse",
+  "description": "A response object for remote providers of AS Router",
+  "type": "object",
+  "version": "0.1.0",
+  "properties": {
+    "messages": {
+      "type": "array",
+      "description": "An array of router messages",
+      "items": {
+        "title": "RouterMessage",
+        "description": "A definition of an individual message",
+        "type": "object",
+        "properties": {
+          "id": {
+            "type": "string",
+            "description": "A unique identifier for the message that should not conflict with any other previous message"
+          },
+          "template": {
+            "type": "string",
+            "description": "An id matching an existing Activity Stream Router template",
+            "enum": ["simple_snippet"]
+          },
+          "content": {
+            "type": "object",
+            "description": "An object containing all variables/props to be rendered in the template. See individual template schemas for details."
+          },
+          "targeting": {
+            "type": "string",
+            "description": "a JEXL expression representing targeting information"
+          },
+          "trigger": {
+            "type": "string",
+            "description": "A string representing what the trigger to show this message is."
+          },
+          "frequency": {
+            "type": "object",
+            "description": "An object containing frequency cap information for a message.",
+            "properties": {
+              "lifetime": {
+                "type": "integer",
+                "description": "The maximum lifetime impressions for a message.",
+                "minimum": 1,
+                "maximum": 100
+              },
+              "custom": {
+                "type": "array",
+                "description": "An array of custom frequency cap definitions.",
+                "items": {
+                  "description": "A frequency cap definition containing time and max impression information",
+                  "type": "object",
+                  "properties": {
+                    "period": {
+                      "oneOf": [
+                        {
+                          "type": "integer",
+                          "description": "Period of time in milliseconds (e.g. 86400000 for one day)"
+                        },
+                        {
+                          "type": "string",
+                          "description": "One of a preset list of short forms for period of time (e.g. 'daily' for one day)",
+                          "enum": ["daily"]
+                        }
+                      ]
+
+                    },
+                    "cap": {
+                      "type": "integer",
+                      "description": "The maximum impressions for the message within the defined period.",
+                      "minimum": 1,
+                      "maximum": 100
+                    }
+                  },
+                  "required": ["period", "cap"]
+                }
+              }
+            }
+          }
+        },
+        "required": ["id", "template", "content"]
+      }
+    }
+  },
+  "required": ["messages"]
+}
rename from browser/extensions/activity-stream/content-src/asrouter/template-utils.js
rename to browser/components/newtab/content-src/asrouter/template-utils.js
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/content-src/asrouter/templates/OnboardingMessage/OnboardingMessage.jsx
@@ -0,0 +1,52 @@
+import {ModalOverlay} from "../../components/ModalOverlay/ModalOverlay";
+import React from "react";
+
+class OnboardingCard extends React.PureComponent {
+  constructor(props) {
+    super(props);
+    this.onClick = this.onClick.bind(this);
+  }
+
+  onClick() {
+    const {props} = this;
+    props.sendUserActionTelemetry({event: "CLICK_BUTTON", message_id: props.id, id: props.UISurface});
+    props.onAction(props.content);
+  }
+
+  render() {
+    const {content} = this.props;
+    return (
+      <div className="onboardingMessage">
+        <div className={`onboardingMessageImage ${content.icon}`} />
+        <div className="onboardingContent">
+          <span>
+            <h3> {content.title} </h3>
+            <p> {content.text} </p>
+          </span>
+          <span>
+            <button tabIndex="1" className="button onboardingButton" onClick={this.onClick}> {content.button_label} </button>
+          </span>
+        </div>
+      </div>
+    );
+  }
+}
+
+export class OnboardingMessage extends React.PureComponent {
+  render() {
+    const {props} = this;
+    return (
+      <ModalOverlay {...props} button_label={"Start Browsing"} title={"Welcome to Firefox"}>
+        <div className="onboardingMessageContainer">
+          {props.bundle.map(message => (
+            <OnboardingCard key={message.id}
+              sendUserActionTelemetry={props.sendUserActionTelemetry}
+              onAction={props.onAction}
+              UISurface={props.UISurface}
+              {...message} />
+          ))}
+        </div>
+      </ModalOverlay>
+    );
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/content-src/asrouter/templates/OnboardingMessage/_OnboardingMessage.scss
@@ -0,0 +1,161 @@
+.onboardingMessageContainer {
+  display: grid;
+  grid-column-gap: 21px;
+  grid-template-columns: auto auto auto;
+  padding-left: 30px;
+  padding-right: 30px;
+
+  // at 850px, the cards go from vertical layout to horizontal layout
+  @media(max-width: 850px) {
+    grid-template-columns: none;
+    grid-template-rows: auto auto auto;
+    padding-left: 110px;
+    padding-right: 110px;
+  }
+}
+
+.onboardingMessage {
+  height: 340px;
+  text-align: center;
+  padding: 13px;
+  font-weight: 200;
+
+  // at 850px, img floats left, content floats right next to it
+  @media(max-width: 850px) {
+    height: 170px;
+    text-align: left;
+    padding: 10px;
+    border-bottom: 1px solid $grey-30;
+    display: flex;
+    margin-bottom: 11px;
+
+    &:last-child {
+      border: 0;
+    }
+
+    .onboardingContent {
+      padding-left: 10px;
+      height: 100%;
+
+      > span > h3 {
+        margin-top: 0;
+        margin-bottom: 4px;
+        font-weight: 400;
+      }
+
+      > span > p {
+        margin-top: 0;
+        line-height: 22px;
+        font-size: 15px;
+      }
+    }
+  }
+
+  @media(max-width: 650px) {
+    height: 250px;
+  }
+
+  .onboardingMessageImage {
+    height: 100px;
+    width: 120px;
+    background-size: 120px;
+    background-position: center center;
+    background-repeat: no-repeat;
+    display: inline-block;
+    vertical-align: middle;
+
+
+    @media(max-width: 850px) {
+      height: 75px;
+      min-width: 80px;
+      background-size: 80px;
+    }
+
+    &.addons {
+      background-image: url('resource://activity-stream/data/content/assets/illustration-addons@2x.png');
+    }
+
+    &.privatebrowsing {
+      background-image: url('resource://activity-stream/data/content/assets/illustration-privatebrowsing@2x.png');
+    }
+
+    &.screenshots {
+      background-image: url('resource://activity-stream/data/content/assets/illustration-screenshots@2x.png');
+    }
+
+    &.gift {
+      background-image: url('resource://activity-stream/data/content/assets/illustration-gift@2x.png');
+    }
+  }
+
+  .onboardingContent {
+    height: 175px;
+
+    > span > h3 {
+      color: $grey-90;
+      margin-bottom: 8px;
+      font-weight: 400;
+    }
+
+    > span > p {
+      color: $grey-60;
+      margin-top: 0;
+      height: 130px;
+      margin-bottom: 12px;
+      font-size: 15px;
+      line-height: 22px;
+
+      @media(max-width: 650px) {
+        margin-bottom: 0;
+      }
+    }
+  }
+
+  .onboardingButton {
+    background-color: $grey-90-10;
+    border: 0;
+    width: 150px;
+    height: 30px;
+    margin-bottom: 23px;
+    padding: 4px 0 6px;
+    font-size: 15px;
+
+    // at 850px, the button shimmies down and to the right
+    @media(max-width: 850px) {
+      float: right;
+      margin-top: -60px;
+      margin-right: -10px;
+    }
+
+    @media(max-width: 650px) {
+      float: none;
+      margin-top: 30px;
+    }
+
+    &:focus,
+    &.active {
+      box-shadow: $shadow-primary;
+      transition: box-shadow 150ms;
+    }
+  }
+
+
+  &::before {
+    content: '';
+    height: 220px;
+    width: 1px;
+    position: absolute;
+    background-color: $grey-30;
+    margin-top: 40px;
+    margin-left: 215px;
+
+    // at 850px, the line goes from vertical to horizontal
+    @media(max-width: 850px) {
+      content: none;
+    }
+  }
+
+  &:last-child::before {
+    content: none;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/content-src/asrouter/templates/SimpleSnippet/SimpleSnippet.jsx
@@ -0,0 +1,53 @@
+import {Button} from "../../components/Button/Button";
+import React from "react";
+import {safeURI} from "../../template-utils";
+import {SnippetBase} from "../../components/SnippetBase/SnippetBase";
+
+const DEFAULT_ICON_PATH = "chrome://branding/content/icon64.png";
+
+export class SimpleSnippet extends React.PureComponent {
+  constructor(props) {
+    super(props);
+    this.onButtonClick = this.onButtonClick.bind(this);
+  }
+
+  onButtonClick() {
+    this.props.sendUserActionTelemetry({event: "CLICK_BUTTON", id: this.props.UISurface});
+  }
+
+  renderTitle() {
+    const {title} = this.props.content;
+    return title ? <h3 className="title">{title}</h3> : null;
+  }
+
+  renderTitleIcon() {
+    const titleIcon = safeURI(this.props.content.title_icon);
+    return titleIcon ? <span className="titleIcon" style={{backgroundImage: `url("${titleIcon}")`}} /> : null;
+  }
+
+  renderButton(className) {
+    const {props} = this;
+    return (<Button
+      className={className}
+      onClick={this.onButtonClick}
+      url={props.content.button_url}
+      color={props.content.button_color}
+      backgroundColor={props.content.button_background_color}>
+      {props.content.button_label}
+    </Button>);
+  }
+
+  render() {
+    const {props} = this;
+    const hasLink = props.content.button_url && props.content.button_type === "anchor";
+    const hasButton = props.content.button_url && !props.content.button_type;
+    const className = `SimpleSnippet${props.content.tall ? " tall" : ""}`;
+    return (<SnippetBase {...props} className={className}>
+      <img src={safeURI(props.content.icon) || DEFAULT_ICON_PATH} className="icon" />
+      <div>
+        {this.renderTitleIcon()} {this.renderTitle()} <p className="body">{props.richText || props.content.text}</p> {hasLink ? this.renderButton("ASRouterAnchor") : null}
+      </div>
+      {hasButton ? <div>{this.renderButton()}</div> : null}
+    </SnippetBase>);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/content-src/asrouter/templates/SimpleSnippet/SimpleSnippet.schema.json
@@ -0,0 +1,95 @@
+{
+  "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_url": {
+      "allOf": [
+        {"$ref": "#/definitions/link_url"},
+        {"description": "A url, button_label links to this"}
+      ]
+    },
+    "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."
+    },
+    "button_type": {
+      "type": "string",
+      "enum": ["anchor", "button"],
+      "description": "(**temporary**, until we get html support in text field Bug 1457233) Style for button, either a regular button or a text link."
+    },
+    "tall": {
+      "type": "boolean",
+      "description": "To be used by fundraising only, increases height to roughly 120px. Defaults to false."
+    },
+    "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": ["text"],
+  "dependencies": {
+    "button_url": ["button_label"],
+    "button_label": ["button_url"],
+    "button_type": ["button_url"],
+    "button_color": ["button_url"],
+    "button_background_color": ["button_url"]
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/content-src/asrouter/templates/SimpleSnippet/_SimpleSnippet.scss
@@ -0,0 +1,43 @@
+.SimpleSnippet {
+  &.tall {
+    padding: 27px 0;
+  }
+
+  .title {
+    display: inline;
+    font-size: inherit;
+    margin: 0;
+  }
+
+  .titleIcon {
+    background-repeat: no-repeat;
+    background-size: 14px;
+    height: 16px;
+    width: 16px;
+    margin-top: 2px;
+    margin-inline-end: 2px;
+    display: inline-block;
+    vertical-align: top;
+  }
+
+  .body {
+    display: inline;
+    margin: 0;
+  }
+
+  .icon {
+    height: 42px;
+    width: 42px;
+    margin-inline-end: 12px;
+    flex-shrink: 0;
+  }
+
+  &.tall .icon {
+    margin-inline-end: 20px;
+  }
+
+  .ASRouterAnchor {
+    color: inherit;
+    text-decoration: underline;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/content-src/components/ASRouterAdmin/ASRouterAdmin.jsx
@@ -0,0 +1,104 @@
+import {ASRouterUtils} from "../../asrouter/asrouter-content";
+import React from "react";
+
+export class ASRouterAdmin extends React.PureComponent {
+  constructor(props) {
+    super(props);
+    this.onMessage = this.onMessage.bind(this);
+    this.findOtherBundledMessagesOfSameTemplate = this.findOtherBundledMessagesOfSameTemplate.bind(this);
+    this.state = {};
+  }
+
+  onMessage({data: action}) {
+    if (action.type === "ADMIN_SET_STATE") {
+      this.setState(action.data);
+    }
+  }
+
+  componentWillMount() {
+    const endpoint = ASRouterUtils.getEndpoint();
+    ASRouterUtils.sendMessage({type: "ADMIN_CONNECT_STATE", data: {endpoint}});
+    ASRouterUtils.addListener(this.onMessage);
+  }
+
+  componentWillUnmount() {
+    ASRouterUtils.removeListener(this.onMessage);
+  }
+
+  findOtherBundledMessagesOfSameTemplate(template) {
+    return this.state.messages.filter(msg => msg.template === template && msg.bundled);
+  }
+
+  handleBlock(msg) {
+    if (msg.bundled) {
+      // If we are blocking a message that belongs to a bundle, block all other messages that are bundled of that same template
+      let bundle = this.findOtherBundledMessagesOfSameTemplate(msg.template);
+      return () => ASRouterUtils.blockBundle(bundle);
+    }
+    return () => ASRouterUtils.blockById(msg.id);
+  }
+
+  handleUnblock(msg) {
+    if (msg.bundled) {
+      // If we are unblocking a message that belongs to a bundle, unblock all other messages that are bundled of that same template
+      let bundle = this.findOtherBundledMessagesOfSameTemplate(msg.template);
+      return () => ASRouterUtils.unblockBundle(bundle);
+    }
+    return () => ASRouterUtils.unblockById(msg.id);
+  }
+
+  handleOverride(id) {
+    return () => ASRouterUtils.overrideMessage(id);
+  }
+
+  renderMessageItem(msg) {
+    const isCurrent = msg.id === this.state.lastMessageId;
+    const isBlocked = this.state.blockList.includes(msg.id);
+    const impressions = this.state.impressions[msg.id] ? this.state.impressions[msg.id].length : 0;
+
+    let itemClassName = "message-item";
+    if (isCurrent) { itemClassName += " current"; }
+    if (isBlocked) { itemClassName += " blocked"; }
+
+    return (<tr className={itemClassName} key={msg.id}>
+      <td className="message-id"><span>{msg.id} <br /></span></td>
+      <td>
+        <button className={`button ${(isBlocked ? "" : " primary")}`} onClick={isBlocked ? this.handleUnblock(msg) : this.handleBlock(msg)}>{isBlocked ? "Unblock" : "Block"}</button>
+       {isBlocked ? null : <button className="button" onClick={this.handleOverride(msg.id)}>Show</button>}
+       <br />({impressions} impressions)
+      </td>
+      <td className="message-summary">
+        <pre>{JSON.stringify(msg, null, 2)}</pre>
+      </td>
+    </tr>);
+  }
+
+  renderMessages() {
+    if (!this.state.messages) {
+      return null;
+    }
+    return (<table><tbody>
+      {this.state.messages.map(msg => this.renderMessageItem(msg))}
+    </tbody></table>);
+  }
+
+  renderProviders() {
+    return (<table><tbody>
+      {this.state.providers.map((provider, i) => (<tr className="message-item" key={i}>
+        <td>{provider.id}</td>
+        <td>{provider.type === "remote" ? <a target="_blank" href={provider.url}>{provider.url}</a> : "(local)"}</td>
+      </tr>))}
+    </tbody></table>);
+  }
+
+  render() {
+    return (<div className="asrouter-admin outer-wrapper">
+      <h1>AS Router Admin</h1>
+      <button className="button primary" onClick={ASRouterUtils.getNextMessage}>Refresh Current Message</button>
+      <h2>Message Providers</h2>
+      {this.state.providers ? this.renderProviders() : null}
+      <h2>Messages</h2>
+      {this.renderMessages()}
+    </div>);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/content-src/components/ASRouterAdmin/ASRouterAdmin.scss
@@ -0,0 +1,78 @@
+
+.asrouter-admin {
+  $border-color: var(--newtab-border-secondary-color);
+  $monospace: 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Mono', 'Droid Sans Mono', 'Source Code Pro', monospace;
+  max-width: 996px;
+  margin: 0 auto;
+  font-size: 14px;
+  // Reset .outer-wrapper styles
+  display: inherit;
+  padding: 0 0 92px;
+
+  h1 {
+    font-weight: 200;
+    font-size: 32px;
+  }
+
+  table {
+    border-collapse: collapse;
+    width: 100%;
+  }
+
+  .message-item {
+    &:first-child td {
+      border-top: 1px solid $border-color;
+    }
+
+    td {
+      vertical-align: top;
+      border-bottom: 1px solid $border-color;
+      padding: 8px;
+
+      &:first-child {
+        border-left: 1px solid $border-color;
+      }
+
+      &:last-child {
+        border-right: 1px solid $border-color;
+      }
+    }
+
+    &.current {
+      .message-id span {
+        background: $yellow-50;
+        padding: 2px 5px;
+
+        [lwt-newtab-brighttext] & {
+          color: $black;
+        }
+      }
+    }
+
+    &.blocked {
+      .message-id,
+      .message-summary {
+        opacity: 0.5;
+      }
+
+      .message-id {
+        opacity: 0.5;
+      }
+    }
+
+    .message-id {
+      font-family: $monospace;
+      font-size: 12px;
+    }
+  }
+
+  pre {
+    background: var(--newtab-textbox-background-color);
+    margin: 0;
+    padding: 8px;
+    font-size: 12px;
+    max-width: 750px;
+    overflow: auto;
+    font-family: $monospace;
+  }
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/newtab/content-src/components/Base/Base.jsx
@@ -0,0 +1,157 @@
+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 {ConfirmDialog} from "content-src/components/ConfirmDialog/ConfirmDialog";
+import {connect} from "react-redux";
+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";
+import {StartupOverlay} from "content-src/components/StartupOverlay/StartupOverlay";
+
+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
+// more features are needed.
+function addLocaleDataForReactIntl(locale) {
+  addLocaleData([{locale, parentLocale: "en"}]);
+}
+
+export class _Base extends React.PureComponent {
+  componentWillMount() {
+    const {App, locale} = this.props;
+    this.sendNewTabRehydrated(App);
+    addLocaleDataForReactIntl(locale);
+    if (this.props.isFirstrun) {
+      global.document.body.classList.add("welcome", "hide-main");
+    }
+  }
+
+  componentDidMount() {
+    // Request state AFTER the first render to ensure we don't cause the
+    // prerendered DOM to be unmounted. Otherwise, NEW_TAB_STATE_REQUEST is
+    // dispatched right after the store is ready.
+    if (this.props.isPrerendered) {
+      this.props.dispatch(ac.AlsoToMain({type: at.NEW_TAB_STATE_REQUEST}));
+      this.props.dispatch(ac.AlsoToMain({type: at.PAGE_PRERENDERED}));
+    }
+  }
+
+  componentWillUnmount() {
+    this.updateTheme();
+  }
+
+  componentWillUpdate({App}) {
+    this.updateTheme();
+    this.sendNewTabRehydrated(App);
+  }
+
+  updateTheme() {
+    const bodyClassName = [
+      "activity-stream",
+      // If we skipped the about:welcome overlay and removed the CSS classes
+      // we don't want to add them back to the Activity Stream view
+      document.body.classList.contains("welcome") ? "welcome" : "",
+      document.body.classList.contains("hide-main") ? "hide-main" : ""
+    ].filter(v => v).join(" ");
+    global.document.body.className = bodyClassName;
+  }
+
+  // The NEW_TAB_REHYDRATED event is used to inform feeds that their
+  // data has been consumed e.g. for counting the number of tabs that
+  // have rendered that data.
+  sendNewTabRehydrated(App) {
+    if (App && App.initialized && !this.renderNotified) {
+      this.props.dispatch(ac.AlsoToMain({type: at.NEW_TAB_REHYDRATED, data: {}}));
+      this.renderNotified = true;
+    }
+  }
+
+  render() {
+    const {props} = this;
+    const {App, locale, strings} = props;
+    const {initialized} = App;
+
+    const prefs = props.Prefs.values;
+    if ((prefs.asrouterExperimentEnabled || prefs.asrouterOnboardingCohort > 0) && window.location.hash === "#asrouter") {
+      return (<ASRouterAdmin />);
+    }
+
+    if (!props.isPrerendered && !initialized) {
+      return null;
+    }
+
+    // Until we can delete the existing onboarding tour, just hide the onboarding button when users are in
+    // the new simplified onboarding experiment. CSS hacks ftw
+    if (prefs.asrouterOnboardingCohort > 0) {
+      global.document.body.classList.add("hide-onboarding");
+    }
+
+    return (<IntlProvider locale={locale} messages={strings}>
+        <ErrorBoundary className="base-content-fallback">
+          <BaseContent {...this.props} />
+        </ErrorBoundary>
+      </IntlProvider>);
+  }
+}
+
+export class BaseContent extends React.PureComponent {
+  constructor(props) {
+    super(props);
+    this.openPreferences = this.openPreferences.bind(this);
+  }
+
+  openPreferences() {
+    this.props.dispatch(ac.OnlyToMain({type: at.SETTINGS_OPEN}));
+    this.props.dispatch(ac.UserEvent({event: "OPEN_NEWTAB_PREFS"}));
+  }
+
+  render() {
+    const {props} = this;
+    const {App} = props;
+    const {initialized} = App;
+    const prefs = props.Prefs.values;
+
+    const shouldBeFixedToTop = PrerenderData.arePrefsValid(name => prefs[name]);
+
+    const outerClassName = [
+      "outer-wrapper",
+      shouldBeFixedToTop && "fixed-to-top"
+    ].filter(v => v).join(" ");
+
+    return (
+      <div>
+        <div className={outerClassName}>
+          <main>
+            {prefs.showSearch &&
+              <div className="non-collapsible-section">
+                <ErrorBoundary>
+                  <Search />
+                </ErrorBoundary>
+              </div>
+            }
+            <div className={`body-wrapper${(initialized ? " on" : "")}`}>
+              {!prefs.migrationExpired &&
+                <div className="non-collapsible-section">
+                  <ManualMigration />
+                </div>
+                }