Bug 1361208 - import latest version of Screenshots (6.6.0) into the tree; r=standard8
authorJared Hirsch <ohai@6a68.net>
Mon, 01 May 2017 16:58:23 -0700
changeset 356020 525326d5ddb15a849d0f8cd29594e88cbda34b0e
parent 356019 340b02a5a42cba525c0433a823bf4b09b3f21623
child 356021 5eaf2d70eded608e64f459e6b255b4725ed95efe
child 356056 1fb88ee057dbc441f59e70e35c8fcf3a7ebb8a9a
push id31754
push userkwierso@gmail.com
push dateWed, 03 May 2017 00:28:51 +0000
treeherdermozilla-central@5eaf2d70eded [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersstandard8
bugs1361208
milestone55.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1361208 - import latest version of Screenshots (6.6.0) into the tree; r=standard8 MozReview-Commit-ID: DICbgINxnoa
browser/extensions/screenshots/bootstrap.js
browser/extensions/screenshots/install.rdf
browser/extensions/screenshots/moz.build
browser/extensions/screenshots/test/browser/.eslintrc.js
browser/extensions/screenshots/test/browser/browser_screenshots_ui_check.js
browser/extensions/screenshots/webextension/_locales/ach/messages.json
browser/extensions/screenshots/webextension/_locales/az/messages.json
browser/extensions/screenshots/webextension/_locales/be/messages.json
browser/extensions/screenshots/webextension/_locales/bg/messages.json
browser/extensions/screenshots/webextension/_locales/bn_BD/messages.json
browser/extensions/screenshots/webextension/_locales/cs/messages.json
browser/extensions/screenshots/webextension/_locales/cy/messages.json
browser/extensions/screenshots/webextension/_locales/de/messages.json
browser/extensions/screenshots/webextension/_locales/dsb/messages.json
browser/extensions/screenshots/webextension/_locales/el/messages.json
browser/extensions/screenshots/webextension/_locales/en_US/messages.json
browser/extensions/screenshots/webextension/_locales/es_AR/messages.json
browser/extensions/screenshots/webextension/_locales/es_CL/messages.json
browser/extensions/screenshots/webextension/_locales/es_ES/messages.json
browser/extensions/screenshots/webextension/_locales/es_MX/messages.json
browser/extensions/screenshots/webextension/_locales/et/messages.json
browser/extensions/screenshots/webextension/_locales/fa/messages.json
browser/extensions/screenshots/webextension/_locales/fi/messages.json
browser/extensions/screenshots/webextension/_locales/fr/messages.json
browser/extensions/screenshots/webextension/_locales/fy_NL/messages.json
browser/extensions/screenshots/webextension/_locales/gu_IN/messages.json
browser/extensions/screenshots/webextension/_locales/he/messages.json
browser/extensions/screenshots/webextension/_locales/hi_IN/messages.json
browser/extensions/screenshots/webextension/_locales/hsb/messages.json
browser/extensions/screenshots/webextension/_locales/hu/messages.json
browser/extensions/screenshots/webextension/_locales/hy_AM/messages.json
browser/extensions/screenshots/webextension/_locales/id/messages.json
browser/extensions/screenshots/webextension/_locales/it/messages.json
browser/extensions/screenshots/webextension/_locales/ja/messages.json
browser/extensions/screenshots/webextension/_locales/kab/messages.json
browser/extensions/screenshots/webextension/_locales/kk/messages.json
browser/extensions/screenshots/webextension/_locales/km/messages.json
browser/extensions/screenshots/webextension/_locales/ko/messages.json
browser/extensions/screenshots/webextension/_locales/lij/messages.json
browser/extensions/screenshots/webextension/_locales/lo/messages.json
browser/extensions/screenshots/webextension/_locales/lt/messages.json
browser/extensions/screenshots/webextension/_locales/ms/messages.json
browser/extensions/screenshots/webextension/_locales/my/messages.json
browser/extensions/screenshots/webextension/_locales/nb_NO/messages.json
browser/extensions/screenshots/webextension/_locales/nl/messages.json
browser/extensions/screenshots/webextension/_locales/nn_NO/messages.json
browser/extensions/screenshots/webextension/_locales/pl/messages.json
browser/extensions/screenshots/webextension/_locales/pt_BR/messages.json
browser/extensions/screenshots/webextension/_locales/pt_PT/messages.json
browser/extensions/screenshots/webextension/_locales/rm/messages.json
browser/extensions/screenshots/webextension/_locales/ro/messages.json
browser/extensions/screenshots/webextension/_locales/ru/messages.json
browser/extensions/screenshots/webextension/_locales/sk/messages.json
browser/extensions/screenshots/webextension/_locales/sl/messages.json
browser/extensions/screenshots/webextension/_locales/sq/messages.json
browser/extensions/screenshots/webextension/_locales/sr/messages.json
browser/extensions/screenshots/webextension/_locales/sv_SE/messages.json
browser/extensions/screenshots/webextension/_locales/te/messages.json
browser/extensions/screenshots/webextension/_locales/th/messages.json
browser/extensions/screenshots/webextension/_locales/tl/messages.json
browser/extensions/screenshots/webextension/_locales/tr/messages.json
browser/extensions/screenshots/webextension/_locales/uk/messages.json
browser/extensions/screenshots/webextension/_locales/ur/messages.json
browser/extensions/screenshots/webextension/_locales/uz/messages.json
browser/extensions/screenshots/webextension/_locales/zh_CN/messages.json
browser/extensions/screenshots/webextension/_locales/zh_TW/messages.json
browser/extensions/screenshots/webextension/assertIsTrusted.js
browser/extensions/screenshots/webextension/background/analytics.js
browser/extensions/screenshots/webextension/background/auth.js
browser/extensions/screenshots/webextension/background/communication.js
browser/extensions/screenshots/webextension/background/deviceInfo.js
browser/extensions/screenshots/webextension/background/main.js
browser/extensions/screenshots/webextension/background/selectorLoader.js
browser/extensions/screenshots/webextension/background/senderror.js
browser/extensions/screenshots/webextension/background/takeshot.js
browser/extensions/screenshots/webextension/build/buildSettings.js
browser/extensions/screenshots/webextension/build/inlineSelectionCss.js
browser/extensions/screenshots/webextension/build/onboardingCss.js
browser/extensions/screenshots/webextension/build/onboardingHtml.js
browser/extensions/screenshots/webextension/build/raven.js
browser/extensions/screenshots/webextension/build/shot.js
browser/extensions/screenshots/webextension/catcher.js
browser/extensions/screenshots/webextension/clipboard.js
browser/extensions/screenshots/webextension/domainFromUrl.js
browser/extensions/screenshots/webextension/icons/back-highlight.svg
browser/extensions/screenshots/webextension/icons/icon-16.svg
browser/extensions/screenshots/webextension/icons/icon-32.svg
browser/extensions/screenshots/webextension/icons/icon-highlight-19.png
browser/extensions/screenshots/webextension/icons/icon-highlight-32.svg
browser/extensions/screenshots/webextension/icons/icon-highlight-38.png
browser/extensions/screenshots/webextension/icons/icon-starred-19.png
browser/extensions/screenshots/webextension/icons/icon-starred-32.svg
browser/extensions/screenshots/webextension/icons/icon-starred-38.png
browser/extensions/screenshots/webextension/icons/icon-welcome-face-without-eyes.svg
browser/extensions/screenshots/webextension/icons/menu-myshot.svg
browser/extensions/screenshots/webextension/icons/onboarding-4.png
browser/extensions/screenshots/webextension/log.js
browser/extensions/screenshots/webextension/makeUuid.js
browser/extensions/screenshots/webextension/manifest.json
browser/extensions/screenshots/webextension/onboarding/slides.html
browser/extensions/screenshots/webextension/onboarding/slides.js
browser/extensions/screenshots/webextension/randomString.js
browser/extensions/screenshots/webextension/selector/callBackground.js
browser/extensions/screenshots/webextension/selector/documentMetadata.js
browser/extensions/screenshots/webextension/selector/shooter.js
browser/extensions/screenshots/webextension/selector/ui.js
browser/extensions/screenshots/webextension/selector/uicontrol.js
browser/extensions/screenshots/webextension/selector/util.js
browser/extensions/screenshots/webextension/sitehelper.js
--- a/browser/extensions/screenshots/bootstrap.js
+++ b/browser/extensions/screenshots/bootstrap.js
@@ -1,15 +1,15 @@
 /* globals AddonManager, Components, LegacyExtensionsUtils, Services,
    XPCOMUtils */
 
 const OLD_ADDON_PREF_NAME = "extensions.jid1-NeEaf3sAHdKHPA@jetpack.deviceIdInfo";
 const OLD_ADDON_ID = "jid1-NeEaf3sAHdKHPA@jetpack";
 const ADDON_ID = "screenshots@mozilla.org";
-const TELEMETRY_ENABLED_PREF = "toolkit.telemetry.enabled";
+const TELEMETRY_ENABLED_PREF = "datareporting.healthreport.uploadEnabled";
 const PREF_BRANCH = "extensions.screenshots.";
 const USER_DISABLE_PREF = "extensions.screenshots.disabled";
 const SYSTEM_DISABLE_PREF = "extensions.screenshots.system-disabled";
 
 const { interfaces: Ci, utils: Cu } = Components;
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
                                   "resource://gre/modules/AddonManager.jsm");
@@ -17,50 +17,50 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/Console.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Services",
                                   "resource://gre/modules/Services.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "LegacyExtensionsUtils",
                                   "resource://gre/modules/LegacyExtensionsUtils.jsm");
 
 let addonResourceURI;
 let appStartupDone;
-const appStartupPromise = new Promise((resolve,reject) => {
+const appStartupPromise = new Promise((resolve, reject) => {
   appStartupDone = resolve;
 });
 
 const prefs = Services.prefs;
 const prefObserver = {
-  register: function() {
-    prefs.addObserver(PREF_BRANCH, this);
+  register() {
+    prefs.addObserver(PREF_BRANCH, this, false); // eslint-disable-line mozilla/no-useless-parameters
   },
 
-  unregister: function() {
-    prefs.removeObserver(PREF_BRANCH, this);
+  unregister() {
+    prefs.removeObserver(PREF_BRANCH, this, false); // eslint-disable-line mozilla/no-useless-parameters
   },
 
-  observe: function(aSubject, aTopic, aData) {
+  observe(aSubject, aTopic, aData) {
     // aSubject is the nsIPrefBranch we're observing (after appropriate QI)
     // aData is the name of the pref that's been changed (relative to aSubject)
     if (aData == USER_DISABLE_PREF || aData == SYSTEM_DISABLE_PREF) {
       // eslint-disable-next-line promise/catch-or-return
       appStartupPromise.then(handleStartup);
     }
   }
 };
 
 const appStartupObserver = {
-  register: function() {
-    Services.obs.addObserver(this, "sessionstore-windows-restored");
+  register() {
+    Services.obs.addObserver(this, "sessionstore-windows-restored", false); // eslint-disable-line mozilla/no-useless-parameters
   },
 
-  unregister: function() {
-    Services.obs.removeObserver(this, "sessionstore-windows-restored", false);
+  unregister() {
+    Services.obs.removeObserver(this, "sessionstore-windows-restored", false); // eslint-disable-line mozilla/no-useless-parameters
   },
 
-  observe: function() {
+  observe() {
     appStartupDone();
     this.unregister();
   }
 }
 
 const APP_STARTUP = 1;
 function startup(data, reason) { // eslint-disable-line no-unused-vars
   if (reason === APP_STARTUP) {
@@ -71,16 +71,23 @@ function startup(data, reason) { // esli
   prefObserver.register();
   addonResourceURI = data.resourceURI;
   // eslint-disable-next-line promise/catch-or-return
   appStartupPromise.then(handleStartup);
 }
 
 function shutdown(data, reason) { // eslint-disable-line no-unused-vars
   prefObserver.unregister();
+  const webExtension = LegacyExtensionsUtils.getEmbeddedExtensionFor({
+    id: ADDON_ID,
+    resourceURI: addonResourceURI
+  });
+  if (webExtension.started) {
+    stop(webExtension);
+  }
 }
 
 function install(data, reason) {} // eslint-disable-line no-unused-vars
 
 function uninstall(data, reason) {} // eslint-disable-line no-unused-vars
 
 function getBoolPref(pref) {
   return prefs.getPrefType(pref) && prefs.getBoolPref(pref);
--- a/browser/extensions/screenshots/install.rdf
+++ b/browser/extensions/screenshots/install.rdf
@@ -7,14 +7,14 @@
     <em:targetApplication>
       <Description>
         <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> <!--Firefox-->
         <em:minVersion>51.0a1</em:minVersion>
         <em:maxVersion>*</em:maxVersion>
       </Description>
     </em:targetApplication>
     <em:type>2</em:type>
-    <em:version>6.3.0</em:version>
+    <em:version>6.6.0</em:version>
     <em:bootstrap>true</em:bootstrap>
     <em:homepageURL>https://pageshot.net/</em:homepageURL>
     <em:multiprocessCompatible>true</em:multiprocessCompatible>
   </Description>
 </RDF>
--- a/browser/extensions/screenshots/moz.build
+++ b/browser/extensions/screenshots/moz.build
@@ -24,32 +24,40 @@ FINAL_TARGET_FILES.features['screenshots
   'webextension/randomString.js',
   'webextension/sitehelper.js'
 ]
 
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ach"] += [
   'webextension/_locales/ach/messages.json'
 ]
 
+FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["az"] += [
+  'webextension/_locales/az/messages.json'
+]
+
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["be"] += [
   'webextension/_locales/be/messages.json'
 ]
 
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["bg"] += [
   'webextension/_locales/bg/messages.json'
 ]
 
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["bn_BD"] += [
   'webextension/_locales/bn_BD/messages.json'
 ]
 
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["cs"] += [
   'webextension/_locales/cs/messages.json'
 ]
 
+FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["cy"] += [
+  'webextension/_locales/cy/messages.json'
+]
+
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["de"] += [
   'webextension/_locales/de/messages.json'
 ]
 
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["dsb"] += [
   'webextension/_locales/dsb/messages.json'
 ]
 
@@ -84,32 +92,40 @@ FINAL_TARGET_FILES.features['screenshots
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["et"] += [
   'webextension/_locales/et/messages.json'
 ]
 
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["fa"] += [
   'webextension/_locales/fa/messages.json'
 ]
 
+FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["fi"] += [
+  'webextension/_locales/fi/messages.json'
+]
+
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["fr"] += [
   'webextension/_locales/fr/messages.json'
 ]
 
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["fy_NL"] += [
   'webextension/_locales/fy_NL/messages.json'
 ]
 
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["gu_IN"] += [
   'webextension/_locales/gu_IN/messages.json'
 ]
 
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["he"] += [
   'webextension/_locales/he/messages.json'
 ]
 
+FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["hi_IN"] += [
+  'webextension/_locales/hi_IN/messages.json'
+]
+
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["hsb"] += [
   'webextension/_locales/hsb/messages.json'
 ]
 
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["hu"] += [
   'webextension/_locales/hu/messages.json'
 ]
 
@@ -132,16 +148,20 @@ FINAL_TARGET_FILES.features['screenshots
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["kab"] += [
   'webextension/_locales/kab/messages.json'
 ]
 
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["kk"] += [
   'webextension/_locales/kk/messages.json'
 ]
 
+FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["km"] += [
+  'webextension/_locales/km/messages.json'
+]
+
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ko"] += [
   'webextension/_locales/ko/messages.json'
 ]
 
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["lij"] += [
   'webextension/_locales/lij/messages.json'
 ]
 
@@ -152,16 +172,20 @@ FINAL_TARGET_FILES.features['screenshots
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["lt"] += [
   'webextension/_locales/lt/messages.json'
 ]
 
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ms"] += [
   'webextension/_locales/ms/messages.json'
 ]
 
+FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["my"] += [
+  'webextension/_locales/my/messages.json'
+]
+
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["nb_NO"] += [
   'webextension/_locales/nb_NO/messages.json'
 ]
 
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["nl"] += [
   'webextension/_locales/nl/messages.json'
 ]
 
@@ -184,16 +208,20 @@ FINAL_TARGET_FILES.features['screenshots
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["pt_PT"] += [
   'webextension/_locales/pt_PT/messages.json'
 ]
 
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["rm"] += [
   'webextension/_locales/rm/messages.json'
 ]
 
+FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ro"] += [
+  'webextension/_locales/ro/messages.json'
+]
+
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ru"] += [
   'webextension/_locales/ru/messages.json'
 ]
 
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["sk"] += [
   'webextension/_locales/sk/messages.json'
 ]
 
@@ -208,16 +236,20 @@ FINAL_TARGET_FILES.features['screenshots
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["sr"] += [
   'webextension/_locales/sr/messages.json'
 ]
 
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["sv_SE"] += [
   'webextension/_locales/sv_SE/messages.json'
 ]
 
+FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["te"] += [
+  'webextension/_locales/te/messages.json'
+]
+
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["th"] += [
   'webextension/_locales/th/messages.json'
 ]
 
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["tl"] += [
   'webextension/_locales/tl/messages.json'
 ]
 
@@ -228,16 +260,20 @@ FINAL_TARGET_FILES.features['screenshots
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["uk"] += [
   'webextension/_locales/uk/messages.json'
 ]
 
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["ur"] += [
   'webextension/_locales/ur/messages.json'
 ]
 
+FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["uz"] += [
+  'webextension/_locales/uz/messages.json'
+]
+
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["zh_CN"] += [
   'webextension/_locales/zh_CN/messages.json'
 ]
 
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["_locales"]["zh_TW"] += [
   'webextension/_locales/zh_TW/messages.json'
 ]
 
@@ -257,33 +293,35 @@ FINAL_TARGET_FILES.features['screenshots
   'webextension/build/inlineSelectionCss.js',
   'webextension/build/onboardingCss.js',
   'webextension/build/onboardingHtml.js',
   'webextension/build/raven.js',
   'webextension/build/shot.js'
 ]
 
 FINAL_TARGET_FILES.features['screenshots@mozilla.org']["webextension"]["icons"] += [
+  'webextension/icons/back-highlight.svg',
   'webextension/icons/back.svg',
   'webextension/icons/cancel.svg',
   'webextension/icons/copy.png',
   'webextension/icons/done.svg',
   'webextension/icons/download.svg',
   'webextension/icons/icon-128.png',
   'webextension/icons/icon-16.png',
+  'webextension/icons/icon-16.svg',
   'webextension/icons/icon-19.png',
   'webextension/icons/icon-256.png',
   'webextension/icons/icon-32.png',
+  'webextension/icons/icon-32.svg',
   'webextension/icons/icon-38.png',
   'webextension/icons/icon-48.png',
   'webextension/icons/icon-64.png',
-  'webextension/icons/icon-highlight-19.png',
-  'webextension/icons/icon-highlight-38.png',
-  'webextension/icons/icon-starred-19.png',
-  'webextension/icons/icon-starred-38.png',
+  'webextension/icons/icon-highlight-32.svg',
+  'webextension/icons/icon-starred-32.svg',
+  'webextension/icons/icon-welcome-face-without-eyes.svg',
   'webextension/icons/menu-fullpage.svg',
   'webextension/icons/menu-myshot.svg',
   'webextension/icons/menu-visible.svg',
   'webextension/icons/onboarding-1.png',
   'webextension/icons/onboarding-2.png',
   'webextension/icons/onboarding-3.png',
   'webextension/icons/onboarding-4.png'
 ]
new file mode 100644
--- /dev/null
+++ b/browser/extensions/screenshots/test/browser/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+  "extends": [
+    "plugin:mozilla/browser-test"
+  ]
+}
--- a/browser/extensions/screenshots/test/browser/browser_screenshots_ui_check.js
+++ b/browser/extensions/screenshots/test/browser/browser_screenshots_ui_check.js
@@ -1,20 +1,21 @@
 "use strict";
 
-/* global add_task, is, promiseScreenshotsEnabled, promiseScreenshotsReset,
-   registerCleanupFunction */
-
 function checkElements(expectPresent, l) {
   for (let id of l) {
     is(!!document.getElementById(id), expectPresent, "element " + id + (expectPresent ? " is" : " is not") + " present");
   }
 }
 
 add_task(function*() {
   yield promiseScreenshotsEnabled();
 
   registerCleanupFunction(function* () {
     yield promiseScreenshotsReset();
   });
 
+  yield BrowserTestUtils.waitForCondition(
+    () => document.getElementById("screenshots_mozilla_org-browser-action"),
+    "Screenshots button should be present", 100, 100);
+
   checkElements(true, ["screenshots_mozilla_org-browser-action"]);
 });
--- a/browser/extensions/screenshots/webextension/_locales/ach/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/ach/messages.json
@@ -98,18 +98,18 @@
     "message": "Cal malubo"
   },
   "tourPrevious": {
     "message": "Cal mukato"
   },
   "tourDone": {
     "message": "Otum"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Tic ki Firefox Screenshots nyuto ni, i yee $TERMSANDPRIVACYNOTICETERMSLINK$ ki $TERMSANDPRIVACYNOTICEPRIVACYLINK$ me Screenshots.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Tic ki Firefox Screenshots nyuto, ni i yee $TERMSANDPRIVACYNOTICETERMSLINK$ ki $TERMSANDPRIVACYNOTICEPRIVACYLINK$ me tic me Cloud pa Firefox.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
new file mode 100644
--- /dev/null
+++ b/browser/extensions/screenshots/webextension/_locales/az/messages.json
@@ -0,0 +1,20 @@
+{
+  "addonAuthorsList": {
+    "message": "Mozilla <screenshots-feedback@mozilla.org>"
+  },
+  "saveScreenshotSelectedArea": {
+    "message": "Saxla"
+  },
+  "saveScreenshotVisibleArea": {
+    "message": "Görünən ərazini saxla"
+  },
+  "cancelScreenshot": {
+    "message": "Ləğv et"
+  },
+  "downloadScreenshot": {
+    "message": "Endir"
+  },
+  "notificationLinkCopiedTitle": {
+    "message": "Keçid köçürüldü"
+  }
+}
\ No newline at end of file
--- a/browser/extensions/screenshots/webextension/_locales/be/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/be/messages.json
@@ -98,18 +98,18 @@
     "message": "Наступны слайд"
   },
   "tourPrevious": {
     "message": "Папярэдні слайд"
   },
   "tourDone": {
     "message": "Гатова"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Выкарыстоўваючы Firefox Screenshots, вы згаджаецеся з яго $TERMSANDPRIVACYNOTICETERMSLINK$ і $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Выкарыстоўваючы Firefox Screenshots, вы згаджаецеся з $TERMSANDPRIVACYNOTICETERMSLINK$ і $TERMSANDPRIVACYNOTICEPRIVACYLINK$ Firefox Cloud Services.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/bg/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/bg/messages.json
@@ -98,26 +98,26 @@
     "message": "Напред"
   },
   "tourPrevious": {
     "message": "Назад"
   },
   "tourDone": {
     "message": "Готово"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Използвайки Firefox Screenshots вие се съгласявате с тези $TERMSANDPRIVACYNOTICETERMSLINK$ и $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Използвайки Firefox Screenshots вие се съгласявате с $TERMSANDPRIVACYNOTICETERMSLINK$ и $TERMSANDPRIVACYNOTICEPRIVACYLINK$ на облачните услуги на Firefox.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
   },
   "termsAndPrivacyNoticeTermsLink": {
-    "message": "Условия"
+    "message": "Условията"
   },
   "termsAndPrivacyNoticyPrivacyLink": {
-    "message": "Политика на поверителност"
+    "message": "Политиката на поверителност"
   }
 }
\ No newline at end of file
--- a/browser/extensions/screenshots/webextension/_locales/bn_BD/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/bn_BD/messages.json
@@ -98,26 +98,15 @@
     "message": "পরবর্তী স্লাইড"
   },
   "tourPrevious": {
     "message": "পূর্ববর্তী স্লাইড"
   },
   "tourDone": {
     "message": "সম্পন্ন"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Firefox Screenshots ব্যবহারের জন্য, আপনি স্ক্রিনশটের $TERMSANDPRIVACYNOTICETERMSLINK$ এবং $TERMSANDPRIVACYNOTICEPRIVACYLINK$ নীতিতে আগ্রহী।",
-    "placeholders": {
-      "termsandprivacynoticetermslink": {
-        "content": "$1"
-      },
-      "termsandprivacynoticeprivacylink": {
-        "content": "$2"
-      }
-    }
-  },
   "termsAndPrivacyNoticeTermsLink": {
     "message": "শর্তাবলী"
   },
   "termsAndPrivacyNoticyPrivacyLink": {
     "message": "গোপনীয়তা নীতি"
   }
 }
\ No newline at end of file
--- a/browser/extensions/screenshots/webextension/_locales/cs/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/cs/messages.json
@@ -98,18 +98,18 @@
     "message": "Další snímek"
   },
   "tourPrevious": {
     "message": "Předchozí snímek"
   },
   "tourDone": {
     "message": "Hotovo"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Používáním služby Firefox Screenshots souhlasíte s jejími $TERMSANDPRIVACYNOTICETERMSLINK$ a $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Používáním služby Firefox Screenshots souhlasíte s $TERMSANDPRIVACYNOTICETERMSLINK$ a $TERMSANDPRIVACYNOTICEPRIVACYLINK$ Firefox Cloud Services.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
new file mode 100644
--- /dev/null
+++ b/browser/extensions/screenshots/webextension/_locales/cy/messages.json
@@ -0,0 +1,123 @@
+{
+  "addonDescription": {
+    "message": "Cymrwch clipiau a lluniau sgrin o'r We a'u cadw dros dro neu'n barhaol."
+  },
+  "addonAuthorsList": {
+    "message": "Mozilla <screenshots-feedback@mozilla.org>"
+  },
+  "contextMenuLabel": {
+    "message": "Cymryd Llun Sgrin Screenshot"
+  },
+  "myShotsLink": {
+    "message": "Fy Lluniau Sgrin"
+  },
+  "screenshotInstructions": {
+    "message": "Llusgwch neu glicio ar y dudalen i ddewis adran. Pwyso ESC i ddiddymu."
+  },
+  "saveScreenshotSelectedArea": {
+    "message": "Cadw"
+  },
+  "saveScreenshotVisibleArea": {
+    "message": "Cadw'r gweladwy"
+  },
+  "saveScreenshotFullPage": {
+    "message": "Cadw tudalen lawn"
+  },
+  "cancelScreenshot": {
+    "message": "Diddymu"
+  },
+  "downloadScreenshot": {
+    "message": "Llwytho i Lawr"
+  },
+  "notificationLinkCopiedTitle": {
+    "message": "Dolen wedi ei Chadw"
+  },
+  "notificationLinkCopiedDetails": {
+    "message": "Mae'r ddolen i'ch llun wedi ei gopïo i'r clipfwrdd. Pwyswch $META_KEY$-V i'w ludo.",
+    "placeholders": {
+      "meta_key": {
+        "content": "$1"
+      }
+    }
+  },
+  "requestErrorTitle": {
+    "message": "Ddim yn gweithio."
+  },
+  "requestErrorDetails": {
+    "message": "Ymddiheuriadau! Nid oedd modd cadw eich llun. Ceisiwch eto'n hwyrach."
+  },
+  "connectionErrorTitle": {
+    "message": "Nid oes modd i ni gysylltu a'ch lluniau sgrin."
+  },
+  "connectionErrorDetails": {
+    "message": "Gwiriwch eich cysylltiad Rhyngrwyd. Os ydych yn gallu cysylltu â'r Rhyngrwyd, efallai bod anhawster dros dro gyda gwasanaeth lluniau sgrin, Firefox Screnshots."
+  },
+  "loginErrorDetails": {
+    "message": "Nid oedd modd i ni gadw eich llun gan fod yna anhawster gyda gwasanaeth Firefox Screenshots. Ceisiwch eto'n hwyrach."
+  },
+  "unshootablePageErrorTitle": {
+    "message": "Nid oes modd tynnu llun sgrin o'r dudalen."
+  },
+  "unshootablePageErrorDetails": {
+    "message": "Nid yw hwn yn dudalen Gwe safonol, felly does dim modd tynnu llun sgrin ohono."
+  },
+  "selfScreenshotErrorTitle": {
+    "message": "Nid oes modd cymryd llun o dudalen lluniau sgrin Firefox Screenshots!"
+  },
+  "genericErrorTitle": {
+    "message": "Www! Mae Firefox Screenshots wedi mynd yn hurt."
+  },
+  "genericErrorDetails": {
+    "message": "Nid ydym yn gwybod beth sydd wedi ddigwydd. Ceisiwch eto neu dynnu llun o dudalen wahanol?"
+  },
+  "tourBodyOne": {
+    "message": "Cymryd, cadw a rhannu lluniau sgrin heb adael Firefox."
+  },
+  "tourHeaderTwo": {
+    "message": "Cipio Dim ond Beth Rydych ei Angen"
+  },
+  "tourBodyTwo": {
+    "message": "Cliciwch a llusgo i gipio rhan o dudalen. Gallwch hofran i amlygu eich dewis."
+  },
+  "tourHeaderThree": {
+    "message": "Yn Ôl eich Dewis"
+  },
+  "tourBodyThree": {
+    "message": "Cadwch eich lluniau wedi eu golygu i'r We ar gyfer rhannu haws, neu eu llwytho i lawr i'ch cyfrifiadur. Gallwch hefyd glicio ar Fy Lluniau i weld pob llun sydd gennych."
+  },
+  "tourHeaderFour": {
+    "message": "Cipio Ffenestri neu Dudalennau Cyfan"
+  },
+  "tourBodyFour": {
+    "message": "Dewiswch y botymau ar y dde uchod i gipio ardal gweladwy mewn ffenestr neu i gipio tudalen gyfan."
+  },
+  "tourSkip": {
+    "message": "SKIP"
+  },
+  "tourNext": {
+    "message": "Sleid Nesaf"
+  },
+  "tourPrevious": {
+    "message": "Sleid Flaenorol"
+  },
+  "tourDone": {
+    "message": "Gorffen"
+  },
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Drwy ddefnyddio Firefox Screenshots, rydych yn cytuno i Firefox Cloud Services $TERMSANDPRIVACYNOTICETERMSLINK$ a $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
+    "placeholders": {
+      "termsandprivacynoticetermslink": {
+        "content": "$1"
+      },
+      "termsandprivacynoticeprivacylink": {
+        "content": "$2"
+      }
+    }
+  },
+  "termsAndPrivacyNoticeTermsLink": {
+    "message": "Telerau"
+  },
+  "termsAndPrivacyNoticyPrivacyLink": {
+    "message": "Hysbysiad Preifatrwydd"
+  }
+}
\ No newline at end of file
--- a/browser/extensions/screenshots/webextension/_locales/de/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/de/messages.json
@@ -98,18 +98,18 @@
     "message": "Nächste Folie"
   },
   "tourPrevious": {
     "message": "Vorherige Folie"
   },
   "tourDone": {
     "message": "Fertig"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Durch die Verwendung von Firefox Screenshots stimmen Sie den entsprechenden $TERMSANDPRIVACYNOTICETERMSLINK$ und dem $TERMSANDPRIVACYNOTICEPRIVACYLINK$ zu.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Durch die Verwendung von Firefox Screenshots stimmen Sie den $TERMSANDPRIVACYNOTICETERMSLINK$ und dem $TERMSANDPRIVACYNOTICEPRIVACYLINK$ von Firefox Cloud Services zu.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/dsb/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/dsb/messages.json
@@ -98,18 +98,18 @@
     "message": "Pśiduce foto"
   },
   "tourPrevious": {
     "message": "Pjerwjejšne foto"
   },
   "tourDone": {
     "message": "Gótowo"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Pśez wužywanje Firefox ScreenShots, zwolijośo do $TERMSANDPRIVACYNOTICETERMSLINK$ a $TERMSANDPRIVACYNOTICEPRIVACYLINK$ Firefox Screenshots.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Pśez wužywanje Firefox ScreenShots, zwolijośo do $TERMSANDPRIVACYNOTICETERMSLINK$ a $TERMSANDPRIVACYNOTICEPRIVACYLINK$ Firefox Cloud Services.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/el/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/el/messages.json
@@ -98,18 +98,18 @@
     "message": "Επόμενη διαφάνεια"
   },
   "tourPrevious": {
     "message": "Προηγούμενη διαφάνεια"
   },
   "tourDone": {
     "message": "Τέλος"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Χρησιμοποιώντας το Firefox Screenshots, συμφωνείτε με τους $TERMSANDPRIVACYNOTICETERMSLINK$ Στιγμιότυπων και τη $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Χρησιμοποιώντας το Firefox Screenshots, συμφωνείτε με τους $TERMSANDPRIVACYNOTICETERMSLINK$ και την $TERMSANDPRIVACYNOTICEPRIVACYLINK$ των Υπηρεσιών Cloud του Firefox.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/en_US/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/en_US/messages.json
@@ -98,18 +98,18 @@
     "message": "Next Slide"
   },
   "tourPrevious": {
     "message": "Previous Slide"
   },
   "tourDone": {
     "message": "Done"
   },
-  "termsAndPrivacyNotice": {
-    "message": "By using Firefox Screenshots, you agree to the Screenshots $TERMSANDPRIVACYNOTICETERMSLINK$ and $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "By using Firefox Screenshots, you agree to the Firefox Cloud Services $TERMSANDPRIVACYNOTICETERMSLINK$ and $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/es_AR/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/es_AR/messages.json
@@ -98,18 +98,18 @@
     "message": "Próxima diapositiva"
   },
   "tourPrevious": {
     "message": "Diapositiva anterior"
   },
   "tourDone": {
     "message": "Listo"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Al usar Firefox Screenshots, aceptás los $TERMSANDPRIVACYNOTICETERMSLINK$ y $TERMSANDPRIVACYNOTICEPRIVACYLINK$ de Screenshots.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "AL usar Firefox Screenshots, aceptás los $TERMSANDPRIVACYNOTICETERMSLINK$ y $TERMSANDPRIVACYNOTICEPRIVACYLINK$ de los servicios en la nube de Firefox.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/es_CL/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/es_CL/messages.json
@@ -98,18 +98,18 @@
     "message": "Siguiente diapositiva"
   },
   "tourPrevious": {
     "message": "Diapositiva anterior"
   },
   "tourDone": {
     "message": "Hecho"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Al usar Firefox Screenshots, aceptas los $TERMSANDPRIVACYNOTICETERMSLINK$ y el $TERMSANDPRIVACYNOTICEPRIVACYLINK$ de Screenshots.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Al usar Firefox Screenshots, aceptas los $TERMSANDPRIVACYNOTICETERMSLINK$ y el $TERMSANDPRIVACYNOTICEPRIVACYLINK$ de Firefox Cloud Services.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/es_ES/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/es_ES/messages.json
@@ -98,18 +98,18 @@
     "message": "Diapositiva siguiente"
   },
   "tourPrevious": {
     "message": "Diapositiva anterior"
   },
   "tourDone": {
     "message": "Hecho"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Al usar Firefox Screenshots, aceptas los $TERMSANDPRIVACYNOTICETERMSLINK$ y el $TERMSANDPRIVACYNOTICEPRIVACYLINK$ de Screenshots.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Al usar Firefox Screenshots, aceptas los $TERMSANDPRIVACYNOTICETERMSLINK$ y el $TERMSANDPRIVACYNOTICEPRIVACYLINK$ de Firefox Cloud Services.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/es_MX/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/es_MX/messages.json
@@ -98,18 +98,18 @@
     "message": "Siguiente diapositiva"
   },
   "tourPrevious": {
     "message": "Diapositiva anterior"
   },
   "tourDone": {
     "message": "Terminado"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Al usar Firefox Screenshots, estás de acuerdo con los $TERMSANDPRIVACYNOTICETERMSLINK$ y con el $TERMSANDPRIVACYNOTICETERMSLINK$ de Screenshots.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Al usar Firefox Screenshots, estás de acuerdo con los servicios de Firefox Cloud $TERMSANDPRIVACYNOTICETERMSLINK$ y $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/et/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/et/messages.json
@@ -98,18 +98,18 @@
     "message": "Järgmine slaid"
   },
   "tourPrevious": {
     "message": "Eelmine slaid"
   },
   "tourDone": {
     "message": "Valmis"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Firefox Screenshots kasutamisel nõustud Screenshots $TERMSANDPRIVACYNOTICETERMSLINK$ ja $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Firefox Screenshots kasutamisel nõustud Firefox Cloud Services $TERMSANDPRIVACYNOTICETERMSLINK$ ja $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/fa/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/fa/messages.json
@@ -98,18 +98,18 @@
     "message": "اسلاید بعدی"
   },
   "tourPrevious": {
     "message": "اسلاید قبلی"
   },
   "tourDone": {
     "message": "انجام شد"
   },
-  "termsAndPrivacyNotice": {
-    "message": "با استفاده از سرویسِ تصاویرِ صفحهٔ فایرفاکس، شما با $TERMSANDPRIVACYNOTICETERMSLINK$ و $TERMSANDPRIVACYNOTICEPRIVACYLINK$ موافقت می‌کنید.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "با استفاده از سرویس تصاویرِ صفحه فایرفاکس، شما با شرایط سرویس‌های ابری فایرفاکس $TERMSANDPRIVACYNOTICETERMSLINK$ و $TERMSANDPRIVACYNOTICEPRIVACYLINK$ موافقت می‌کنید.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
new file mode 100644
--- /dev/null
+++ b/browser/extensions/screenshots/webextension/_locales/fi/messages.json
@@ -0,0 +1,23 @@
+{
+  "addonAuthorsList": {
+    "message": "Mozilla <screenshots-feedback@mozilla.org>"
+  },
+  "saveScreenshotSelectedArea": {
+    "message": "Tallenna"
+  },
+  "saveScreenshotVisibleArea": {
+    "message": "Tallenna näkyvä osuus"
+  },
+  "saveScreenshotFullPage": {
+    "message": "Tallenna koko sivu"
+  },
+  "cancelScreenshot": {
+    "message": "Peruuta"
+  },
+  "downloadScreenshot": {
+    "message": "Lataa"
+  },
+  "notificationLinkCopiedTitle": {
+    "message": "Linkki kopioitu"
+  }
+}
\ No newline at end of file
--- a/browser/extensions/screenshots/webextension/_locales/fr/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/fr/messages.json
@@ -60,17 +60,17 @@
   },
   "unshootablePageErrorDetails": {
     "message": "Impossible d’effectuer une capture d’écran, car cette page web n’est pas standard."
   },
   "selfScreenshotErrorTitle": {
     "message": "Vous ne pouvez pas effectuer une capture d’écran d’une page Firefox Screenshots."
   },
   "genericErrorTitle": {
-    "message": "Firefox Screenshots semble avoir un petit problème."
+    "message": "Firefox Screenshots semble avoir un problème."
   },
   "genericErrorDetails": {
     "message": "Un problème non identifié est survenu. Vous pouvez réessayer ou effectuer une capture d’écran d’une autre page."
   },
   "tourBodyOne": {
     "message": "Effectuez des captures d’écran, enregistrez et partagez-les sans quitter Firefox."
   },
   "tourHeaderTwo": {
@@ -98,18 +98,18 @@
     "message": "Écran suivant"
   },
   "tourPrevious": {
     "message": "Écran précédent"
   },
   "tourDone": {
     "message": "Terminé"
   },
-  "termsAndPrivacyNotice": {
-    "message": "En utilisant Firefox Screenshots, vous acceptez les $TERMSANDPRIVACYNOTICETERMSLINK$ et la $TERMSANDPRIVACYNOTICEPRIVACYLINK$ de Screenshots.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "En utilisant Firefox Screenshots, vous acceptez les $TERMSANDPRIVACYNOTICETERMSLINK$ et la $TERMSANDPRIVACYNOTICEPRIVACYLINK$ des services en ligne de Firefox.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/fy_NL/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/fy_NL/messages.json
@@ -98,18 +98,18 @@
     "message": "Folgjende ôfbylding"
   },
   "tourPrevious": {
     "message": "Foarige ôfbylding"
   },
   "tourDone": {
     "message": "Dien"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Troch Firefox Screenshots te brûken, gean jo akkoard mei de $TERMSANDPRIVACYNOTICETERMSLINK$ en $TERMSANDPRIVACYNOTICEPRIVACYLINK$ fan Screenshots.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Troch Firefox Screenshots te brûken, geane jo akkoard mei de $TERMSANDPRIVACYNOTICETERMSLINK$ en $TERMSANDPRIVACYNOTICEPRIVACYLINK$ fan Firefox-cloudtsjinsten.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/gu_IN/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/gu_IN/messages.json
@@ -98,18 +98,18 @@
     "message": "આગલી સ્લાઇડ"
   },
   "tourPrevious": {
     "message": "પહેલાની સ્લાઇડ"
   },
   "tourDone": {
     "message": "થઈ ગયું"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Firefox સ્ક્રીનશોટ્સ વાપરીને, તમે સ્ક્રીનશૉટ્સ થી સંમત છો $TERMSANDPRIVACYNOTICETERMSLINK$ અને $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Firefox સ્ક્રીનશોટ્સ વાપરીને, તમે Firefox Cloud સેવાઓ સાથે સંમત થાઓ છો $TERMSANDPRIVACYNOTICETERMSLINK$ અને $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/he/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/he/messages.json
@@ -85,10 +85,39 @@
   "tourBodyThree": {
     "message": "שמירת הצילומים החתוכים שלך לאחסון מקוון לצורך שיתוף פשוט יותר, או להוריד אותם למחשב שלך. ניתן גם ללחוץ על כפתור הצילומים שלי כדי למצוא את כל הצילומים שצילמת."
   },
   "tourHeaderFour": {
     "message": "לצלם חלונות או דפים שלמים"
   },
   "tourBodyFour": {
     "message": "נא לבחור בכפתורים שבחלק העליון כדי לצלם את האזור הגלוי בחלון או לצלם את הדף כולו."
+  },
+  "tourSkip": {
+    "message": "דילוג"
+  },
+  "tourNext": {
+    "message": "השקופית הבאה"
+  },
+  "tourPrevious": {
+    "message": "השקופית הקודמת"
+  },
+  "tourDone": {
+    "message": "סיום"
+  },
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "מעצם השימוש ב־Firefox Screenshots הכללים של שירותי הענן של Firefox‏ $TERMSANDPRIVACYNOTICETERMSLINK$ ו$TERMSANDPRIVACYNOTICEPRIVACYLINK$ מוסכמים עליך.",
+    "placeholders": {
+      "termsandprivacynoticetermslink": {
+        "content": "$1"
+      },
+      "termsandprivacynoticeprivacylink": {
+        "content": "$2"
+      }
+    }
+  },
+  "termsAndPrivacyNoticeTermsLink": {
+    "message": "תנאים"
+  },
+  "termsAndPrivacyNoticyPrivacyLink": {
+    "message": "הצהרת פרטיות"
   }
 }
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/extensions/screenshots/webextension/_locales/hi_IN/messages.json
@@ -0,0 +1,123 @@
+{
+  "addonDescription": {
+    "message": "वेब से फ़ोटो और स्क्रीनशॉट लें और उन्हें अस्थायी या स्थायी रूप से सहेजें."
+  },
+  "addonAuthorsList": {
+    "message": "Mozilla <screenshots-feedback@mozilla.org>"
+  },
+  "contextMenuLabel": {
+    "message": "स्क्रीनशॉट लें"
+  },
+  "myShotsLink": {
+    "message": "मेरे चित्र"
+  },
+  "screenshotInstructions": {
+    "message": "किसी क्षेत्र को चुनने के लिए पृष्ठ पर खींचें या क्लिक करें. रद्द करने के लिए ESC दबाएँ."
+  },
+  "saveScreenshotSelectedArea": {
+    "message": "सहेजें"
+  },
+  "saveScreenshotVisibleArea": {
+    "message": "दृश्यमान सहेजें"
+  },
+  "saveScreenshotFullPage": {
+    "message": "पूर्ण पृष्ठ सहेजें"
+  },
+  "cancelScreenshot": {
+    "message": "रद्द करें"
+  },
+  "downloadScreenshot": {
+    "message": "डाउनलोड करें"
+  },
+  "notificationLinkCopiedTitle": {
+    "message": "लिंक की नक़ल की गयी"
+  },
+  "notificationLinkCopiedDetails": {
+    "message": "आपके शॉट के लिंक क्लिपबोर्ड पर कॉपी किए गए हैं. पेस्ट करने के लिए $META_KEY$-V दबाएँ.",
+    "placeholders": {
+      "meta_key": {
+        "content": "$1"
+      }
+    }
+  },
+  "requestErrorTitle": {
+    "message": "कार्यरत नहीं है."
+  },
+  "requestErrorDetails": {
+    "message": "क्षमा करें! हम आपके शॉट को सहेज़ नहीं सके. कृपया बाद में पुन: प्रयास करें."
+  },
+  "connectionErrorTitle": {
+    "message": "हम आपके स्क्रीनशॉट से जुड़ नहीं सकते हैं."
+  },
+  "connectionErrorDetails": {
+    "message": "कृपया अपने इंटरनेट संपर्क की जाँच करें. यदि आप इंटरनेट से जुड़ने में सक्षम हैं, तो Firefox स्क्रीनशॉट सेवा के साथ एक अस्थायी समस्या हो सकती है."
+  },
+  "loginErrorDetails": {
+    "message": "हम आपका शॉट सहेज नहीं सके क्योंकि Firefox स्क्रीनशॉट सेवा में कोई समस्या है. कृपया बाद में पुन: प्रयास करें."
+  },
+  "unshootablePageErrorTitle": {
+    "message": "हम इस पृष्ठ का स्क्रीनशॉट नहीं ले सकते."
+  },
+  "unshootablePageErrorDetails": {
+    "message": "यह एक मानक वेब पेज नहीं है, इसलिए आप इसका स्क्रीनशॉट नहीं ले सकते."
+  },
+  "selfScreenshotErrorTitle": {
+    "message": "आप एक Firefox स्क्रीनशॉट पृष्ठ का शॉट नहीं ले सकते!"
+  },
+  "genericErrorTitle": {
+    "message": "ओह! Firefox स्क्रीनशॉट बिगड़ गया."
+  },
+  "genericErrorDetails": {
+    "message": "हम सुनिश्चित नहीं हैं कि अभी क्या हुआ. पुन: प्रयास या एक भिन्न पृष्ठ का एक शॉट लेना चाहते हैं?"
+  },
+  "tourBodyOne": {
+    "message": "Firefox छोड़े बिना स्क्रीनशॉट लें, सहेजें, और साझा करें."
+  },
+  "tourHeaderTwo": {
+    "message": "जो आप चाहते हैं उसे कैद करें"
+  },
+  "tourBodyTwo": {
+    "message": "पृष्ठ के बस एक हिस्से को कैद करने के लिए क्लिक करें और खींचें. आप अपने चयन को हाइलाइट करने के लिए भी जा सकते हैं."
+  },
+  "tourHeaderThree": {
+    "message": "जैसा आप इसे चाहते हैं"
+  },
+  "tourBodyThree": {
+    "message": "आसानी से साझा करने या उन्हें अपने कंप्यूटर पर डाउनलोड करने के लिए अपने क्रॉप किये गये शॉट को वेब पर सहेजें. आपके द्वारा लिए गये सभी शॉट्स को ढूंढने के लिए आप मेरे शॉट्स बटन पर भी क्लिक कर सकते हैं."
+  },
+  "tourHeaderFour": {
+    "message": "विंडोज़ या संपूर्ण पृष्ठों को कैद करें"
+  },
+  "tourBodyFour": {
+    "message": "विंडो में दिखाई देने वाले क्षेत्र या एक पूरे पृष्ठ को कैद करने के लिए ऊपर में दाहिनी तरफ़ के बटन का चयन करें."
+  },
+  "tourSkip": {
+    "message": "SKIP"
+  },
+  "tourNext": {
+    "message": "अगली स्लाइड"
+  },
+  "tourPrevious": {
+    "message": "पिछली स्लाइड"
+  },
+  "tourDone": {
+    "message": "पूर्ण"
+  },
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Firefox स्क्रीनशॉट का उपयोग करके, आप Firefox क्लाउड सेवाओं $TERMSANDPRIVACYNOTICETERMSLINK$ और $TERMSANDPRIVACYNOTICEPRIVACYLINK$ के लिए सहमत हैं.",
+    "placeholders": {
+      "termsandprivacynoticetermslink": {
+        "content": "$1"
+      },
+      "termsandprivacynoticeprivacylink": {
+        "content": "$2"
+      }
+    }
+  },
+  "termsAndPrivacyNoticeTermsLink": {
+    "message": "शर्तें"
+  },
+  "termsAndPrivacyNoticyPrivacyLink": {
+    "message": "गोपनीयता सूचना"
+  }
+}
\ No newline at end of file
--- a/browser/extensions/screenshots/webextension/_locales/hsb/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/hsb/messages.json
@@ -98,18 +98,18 @@
     "message": "Přichodne foto"
   },
   "tourPrevious": {
     "message": "Předchadne foto"
   },
   "tourDone": {
     "message": "Hotowo"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Přez wužiwanje Firefox ScreenShots, zwoliće do $TERMSANDPRIVACYNOTICETERMSLINK$ a $TERMSANDPRIVACYNOTICEPRIVACYLINK$ Firefox Screenshots.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Přez wužiwanje Firefox ScreenShots, zwoliće do $TERMSANDPRIVACYNOTICETERMSLINK$ a $TERMSANDPRIVACYNOTICEPRIVACYLINK$ Firefox Cloud Services.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/hu/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/hu/messages.json
@@ -98,18 +98,18 @@
     "message": "Következő dia"
   },
   "tourPrevious": {
     "message": "Előző dia"
   },
   "tourDone": {
     "message": "Kész"
   },
-  "termsAndPrivacyNotice": {
-    "message": "A Firefox képernyőképek használatával, Ön beleegyezik a képernyőképek $TERMSANDPRIVACYNOTICETERMSLINK$ és $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "A Firefox képernyőképek használatával beleegyezik a Firefox felhőszolgáltatások $TERMSANDPRIVACYNOTICETERMSLINK$ és $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/hy_AM/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/hy_AM/messages.json
@@ -97,10 +97,27 @@
   "tourNext": {
     "message": "Հաջորդ սահիկը"
   },
   "tourPrevious": {
     "message": "Նախորդ սահիկը"
   },
   "tourDone": {
     "message": "Պատրաստ է"
+  },
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Օգտագործելով Firefox Screenshots-ը՝ դուք ընդունում եք Firefox Cloud ծառայությունների $TERMSANDPRIVACYNOTICETERMSLINK$ը և $TERMSANDPRIVACYNOTICEPRIVACYLINK$ը:",
+    "placeholders": {
+      "termsandprivacynoticetermslink": {
+        "content": "$1"
+      },
+      "termsandprivacynoticeprivacylink": {
+        "content": "$2"
+      }
+    }
+  },
+  "termsAndPrivacyNoticeTermsLink": {
+    "message": "Պայմաններ"
+  },
+  "termsAndPrivacyNoticyPrivacyLink": {
+    "message": "Գաղտնիության ծանուցում"
   }
 }
\ No newline at end of file
--- a/browser/extensions/screenshots/webextension/_locales/id/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/id/messages.json
@@ -98,18 +98,18 @@
     "message": "Salindia Selanjutnya"
   },
   "tourPrevious": {
     "message": "Salindia Sebelumnya"
   },
   "tourDone": {
     "message": "Selesai"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Dengan menggunakan Firefox Screenshots, Anda setuju dengan $TERMSANDPRIVACYNOTICETERMSLINK$ dan $TERMSANDPRIVACYNOTICEPRIVACYLINK$ Screenshots.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Dengan menggunakan Firefox Screenshots, Anda setuju dengan $TERMSANDPRIVACYNOTICETERMSLINK$ dan $TERMSANDPRIVACYNOTICEPRIVACYLINK$ Firefox Cloud Services.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/it/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/it/messages.json
@@ -98,18 +98,18 @@
     "message": "Schermata successiva"
   },
   "tourPrevious": {
     "message": "Schermata precedente"
   },
   "tourDone": {
     "message": "Fine"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Utilizzando Firefox Screenshots si accettano le $TERMSANDPRIVACYNOTICETERMSLINK$ e l’$TERMSANDPRIVACYNOTICEPRIVACYLINK$ del servizio.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Utilizzando Firefox Screenshots si accettano le $TERMSANDPRIVACYNOTICETERMSLINK$ e l’$TERMSANDPRIVACYNOTICEPRIVACYLINK$ di Firefox Cloud Services.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/ja/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/ja/messages.json
@@ -98,18 +98,18 @@
     "message": "次のスライド"
   },
   "tourPrevious": {
     "message": "前のスライド"
   },
   "tourDone": {
     "message": "完了"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Firefox Screenshots を使うことで、あなたは Screenshots の $TERMSANDPRIVACYNOTICETERMSLINK$ と $TERMSANDPRIVACYNOTICEPRIVACYLINK$ に同意したことになります。",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Firefox Screenshots を使うことで、あなたは Firefox Cloud Services の $TERMSANDPRIVACYNOTICETERMSLINK$ と $TERMSANDPRIVACYNOTICEPRIVACYLINK$ に同意したことになります。",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/kab/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/kab/messages.json
@@ -1,11 +1,11 @@
 {
   "addonDescription": {
-    "message": "Ṭṭef imrayen akked igdilen si Web sakin sekles-iten s wudem askudan neɣ s wudem yezgan."
+    "message": "Ṭṭef imrayen akked igdilen si Web sakin sekles-iten s wudem askudan neγ s wudem yezgan."
   },
   "addonAuthorsList": {
     "message": "Mozilla <screenshots-feedback@mozilla.org>"
   },
   "contextMenuLabel": {
     "message": "Ṭṭef agdil"
   },
   "myShotsLink": {
@@ -98,18 +98,18 @@
     "message": "Tigri n zdat"
   },
   "tourPrevious": {
     "message": "Tigri n deffir"
   },
   "tourDone": {
     "message": "Immed"
   },
-  "termsAndPrivacyNotice": {
-    "message": "S useqdec Firefox Screenshots,  ad tqebleḍ $TERMSANDPRIVACYNOTICETERMSLINK$ n Screenshots akked $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "S useqdec n Firefox Screenshots, ad tqebleḍ tiwuriwin n usigna Firefox $TERMSANDPRIVACYNOTICETERMSLINK$ akked $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/kk/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/kk/messages.json
@@ -44,42 +44,80 @@
     "message": "Жұмыс істемейді."
   },
   "requestErrorDetails": {
     "message": "Кешіріңіз! Сіздің скриншотыңызды сақтай алмадық. Кейінірек қайталап көріңіз."
   },
   "connectionErrorTitle": {
     "message": "Скриншоттарыңызға байланыса алмадық."
   },
+  "connectionErrorDetails": {
+    "message": "Интернетпен байланысыңызды тексеріңіз. Егер сізде интернетпен байланыс бар болса, онда Firefox скриншоттары қызметімен уақытша мәселелер болуы мүмкін."
+  },
+  "loginErrorDetails": {
+    "message": "Скриншотыңызды сақтай алмадық, өйткені Firefox скриншоттары қызметімен мәселе бар болып тұр. Кейінірек қайталап көріңіз."
+  },
   "unshootablePageErrorTitle": {
     "message": "Бұл беттің скриншотын түсіре алмаймыз."
   },
   "unshootablePageErrorDetails": {
     "message": "Бұл қалыпты веб беті емес, сондықтан оның скриншотын түсіру мүмкін емес."
   },
   "selfScreenshotErrorTitle": {
     "message": "Firefox скриншоттары бетінің скриншотын түсіру мүмкін емес!"
   },
   "genericErrorTitle": {
     "message": "Қап! Firefox скриншоттары жасамай қалған сияқты."
   },
+  "genericErrorDetails": {
+    "message": "Не болғанын білмейміз. Қайталап көресіз бе, немесе басқа парақтың скриншотын түсіріп көресіз бе?"
+  },
   "tourBodyOne": {
     "message": "Firefox ішінен скриншоттарды түсіру, сақтау және олармен бөлісу."
   },
   "tourHeaderTwo": {
     "message": "Тек керек нәрсені түсіріңіз"
   },
+  "tourBodyTwo": {
+    "message": "Беттің тек бір бөлігін түсіру үшін тышқанды шертіп, тартыңыз. Таңдауыңызды түспен ерекшелеу үшін үстінен өткізсеңіз болады."
+  },
   "tourHeaderThree": {
     "message": "Өзіңізге керек түрде"
   },
+  "tourBodyThree": {
+    "message": "Қиылған скриншоттарыңыздбен оңай бөлісу үшін оларды интернетте сақтаңыз, немесе өз компьютеріңізге жүктеп алыңыз. Сонымен қатар, сіз жасаған барлық скриншоттарды табу үшін Менің скриншоттарым батырмасына шерте аласыз."
+  },
+  "tourHeaderFour": {
+    "message": "Терезелер немесе толық беттерді түсіріңіз"
+  },
+  "tourBodyFour": {
+    "message": "Жоғарғы оң жақта орналасқан батырмаларды терезенің көрінетін аймағын, немесе толық бетті түсіру үшін қолданыңыз."
+  },
   "tourSkip": {
     "message": "Аттап кету"
   },
   "tourNext": {
     "message": "Келесі слайд"
   },
   "tourPrevious": {
     "message": "Алдыңғы слайд"
   },
   "tourDone": {
     "message": "Дайын"
+  },
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Firefox скриншоттарын қолдану арқылы, сіз Firefox бұлттық қызметтерінің $TERMSANDPRIVACYNOTICETERMSLINK$ және $TERMSANDPRIVACYNOTICEPRIVACYLINK$ келісесіз.",
+    "placeholders": {
+      "termsandprivacynoticetermslink": {
+        "content": "$1"
+      },
+      "termsandprivacynoticeprivacylink": {
+        "content": "$2"
+      }
+    }
+  },
+  "termsAndPrivacyNoticeTermsLink": {
+    "message": "Қолдану шарттары"
+  },
+  "termsAndPrivacyNoticyPrivacyLink": {
+    "message": "Жекелік ескертуі"
   }
 }
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/extensions/screenshots/webextension/_locales/km/messages.json
@@ -0,0 +1,5 @@
+{
+  "saveScreenshotSelectedArea": {
+    "message": "រក្សា​ទុក"
+  }
+}
\ No newline at end of file
--- a/browser/extensions/screenshots/webextension/_locales/ko/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/ko/messages.json
@@ -98,18 +98,18 @@
     "message": "다음 슬라이드"
   },
   "tourPrevious": {
     "message": "이전 슬라이드"
   },
   "tourDone": {
     "message": "완료"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Firefox Screenshots를 사용하므로써, $TERMSANDPRIVACYNOTICETERMSLINK$와 $TERMSANDPRIVACYNOTICEPRIVACYLINK$에 동의하게 됩니다.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Firefox Screenshots을 사용함으로써, Firefox Cloud Services $TERMSANDPRIVACYNOTICETERMSLINK$과 $TERMSANDPRIVACYNOTICEPRIVACYLINK$에 동의하게 됩니다.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/lij/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/lij/messages.json
@@ -97,10 +97,27 @@
   "tourNext": {
     "message": "Pròscima schermâ"
   },
   "tourPrevious": {
     "message": "Schermâ de primma"
   },
   "tourDone": {
     "message": "Fæto"
+  },
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Se ti deuvi Firefox Screenshots, ti e d'acordio con $TERMSANDPRIVACYNOTICETERMSLINK$ e $TERMSANDPRIVACYNOTICEPRIVACYLINK$ de Firefox Cloud Services.",
+    "placeholders": {
+      "termsandprivacynoticetermslink": {
+        "content": "$1"
+      },
+      "termsandprivacynoticeprivacylink": {
+        "content": "$2"
+      }
+    }
+  },
+  "termsAndPrivacyNoticeTermsLink": {
+    "message": "Termini"
+  },
+  "termsAndPrivacyNoticyPrivacyLink": {
+    "message": "Informativa in sciâ privacy"
   }
 }
\ No newline at end of file
--- a/browser/extensions/screenshots/webextension/_locales/lo/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/lo/messages.json
@@ -1,12 +1,24 @@
 {
+  "addonDescription": {
+    "message": "ຖ່າຍຄຣິບ ແລະ ພາບຫນ້າຈໍຈາກຫນ້າເວັບ ແລ້ວບັນທຶກໄວ້ຊົ່ວຄາວ ຫລື ຖາວອນ."
+  },
   "addonAuthorsList": {
     "message": "Mozilla <screenshots-feedback@mozilla.org>"
   },
+  "contextMenuLabel": {
+    "message": "ຖ່າຍພາບຫນ້າຈໍ"
+  },
+  "myShotsLink": {
+    "message": "ພາບຂອງຂ້ອຍ"
+  },
+  "screenshotInstructions": {
+    "message": "ລາກ ຫລື ຄິກໃສ່ຫນ້າເວັບເພື່ອເລືອກເອົາບ່ອນທີ່ຕ້ອງການ. ກົດ ESC ເພື່ອຍົກເລີກ."
+  },
   "saveScreenshotSelectedArea": {
     "message": "ບັນທຶກ"
   },
   "saveScreenshotVisibleArea": {
     "message": "ບັນທຶກສ່ວນທີ່ເບິງເຫັນໄດ້"
   },
   "saveScreenshotFullPage": {
     "message": "ບັນທຶກຫມົດຫນ້າ"
@@ -15,24 +27,97 @@
     "message": ""
   },
   "downloadScreenshot": {
     "message": "ດາວໂຫລດ"
   },
   "notificationLinkCopiedTitle": {
     "message": "ໄດ້ສຳເນົາລີ້ງໄວ້ແລ້ວ"
   },
+  "notificationLinkCopiedDetails": {
+    "message": "ລີ້ງໄປຫາຮູບພາບຂອງທ່ານໄດ້ຖືກບັນທຶກໄວ້ໃນຄຣິບບອດ. ກົດ $META_KEY$-V ເພື່ອວາງ.",
+    "placeholders": {
+      "meta_key": {
+        "content": "$1"
+      }
+    }
+  },
+  "requestErrorTitle": {
+    "message": "ໃຊ້ວຽກບໍ່ໄດ້."
+  },
+  "requestErrorDetails": {
+    "message": "ຂໍອະໄພ! ພວກເຮົາບໍ່ສາມາດບັນທຶກພາບຂອງທ່ານໄດ້. ກະລູນາລອງໃຫມ່ອີກຄັ້ງ."
+  },
+  "connectionErrorTitle": {
+    "message": "ພວກເຮົາບໍ່ສາມາດເຊື່ອມຕໍ່ໄປຫາພາບຫນ້າຈໍຂອງທ່ານໄດ້."
+  },
+  "connectionErrorDetails": {
+    "message": "ກະລູນາກວດເບິງການເຊື່ອມຕໍ່ກັບອິນເຕີເນັດຂອງທ່ານ. ຖ້າຫາກວ່າທ່ານສາມາດເຊື່ອມຕໍ່ກັບອິນເຕີເນັດໄດ້ແມ່ນ ບໍລິການພາບຖ່າຍຫນ້າຈໍຂອງ Firefox ອາດຈະເກີດມີບັນຫາຊົ່ວຄາວ."
+  },
+  "loginErrorDetails": {
+    "message": "ພວກເຮົາບໍ່ສາມາດບັນທຶກພາບຖ່າຍຂອງທ່ານໄດ້ ເພາະວ່າບໍລິການພາບຖ່າຍຫນ້າຈໍຂອງ Firefox ໄດ້ເກີດມີບັນຫາ. ກະລູນາລອງໃຫມ່ອີກຄັ້ງ."
+  },
   "unshootablePageErrorTitle": {
     "message": "ພວກເຮົາບໍ່ສາມາດຖ່າຍຮູບຫນ້າຈໍຂອງຫນ້ານີ້ໄດ້."
   },
+  "unshootablePageErrorDetails": {
+    "message": "ນີ້ບໍ່ແມ່ນຫນ້າເວັບມາດຕະຖານ, ສະນັ້ນທ່ານຈຶ່ງບໍ່ສາມາດຖ່າຍພາບຫນ້າຈໍໄດ້."
+  },
+  "selfScreenshotErrorTitle": {
+    "message": "ທ່ານບໍ່ສາມາດຖ່າຍພາບຫນ້າຈໍຂອງ Firefox ໄດ້!"
+  },
+  "genericErrorTitle": {
+    "message": "ໂອ! Firefox Screenshots ລວນ."
+  },
+  "genericErrorDetails": {
+    "message": "ພວກເຮົາບໍ່ແນ່ໃຈວ່າມັນຫາກະເກີດຫຍັງຂື້ນ. ກະລຸນາລອງໃຫມ່ອີກຄັ້ງ ຫລື ຖ່າຍພາບຫນ້າຈໍອື່ນລອງເບິງ"
+  },
+  "tourBodyOne": {
+    "message": "ຖ່າຍ, ບັນທຶກ ແລະ ແບ່ງປັນພາບຫນ້າຈໍໂດຍບໍ່ຕ້ອງອອກຈາກ Firefox."
+  },
+  "tourHeaderTwo": {
+    "message": "ຖ່າຍພາບຕາມທີ່ທ່ານຕ້ອງການ"
+  },
+  "tourBodyTwo": {
+    "message": "ຄິກ ຫລື ລາກເພື່ອຖ່າຍພາບສະເພາະບາງສ່ວນຂອງຫນ້າເວັບ. ພ້ອມດຽວກັນນັ້ນທ່ານຍັງສາມາດເລື່ອນມາເພື່ອເນັ້ນພາບທີ່ທ່ານເລືອກ."
+  },
+  "tourHeaderThree": {
+    "message": "ຕາມທີ່ທ່ານມັກ"
+  },
+  "tourBodyThree": {
+    "message": "ບັນທຶກຮູບພາບທີ່ທ່ານໄດ້ຄັອບເອົາໄວ້ລົງໄປໄວ້ໃນເວັບເພື່ອເຮັດໃຫ້ແບ່ງປັນໄດ້ງ່າຍ ຫລື ດາວໂຫລດໄປໄວ້ໃນຄອມພິວເຕີຂອງທ່ານ. ທ່ານຍັງສາມາດຄິກໃສ່ໃນປຸ່ມກົດ \"ຮູບພາບຂອງຂ້ອຍ\" ເພື່ອຊອກຫາຮູບພາບທັງຫມົດທີ່ທ່ານໄດ້ຖ່າຍເອົາໄວ້."
+  },
+  "tourHeaderFour": {
+    "message": "ຖ່າຍພາບວິນໂດ ຫລື ຫມົດທັ້ງຫນ້າ"
+  },
+  "tourBodyFour": {
+    "message": "ເລືອກປຸ່ມກົດທີ່ຢູ່ເທິງເບື້ອງຂວາມືເພື່ອຈັບພາບໃນບໍລິເວນທີ່ເບິງເຫັນໄດ້ໃນວິນໂດ ຫລື ເພື່ອຈັບພາບທັງຫມົດໃນຫນ້າເວັບ."
+  },
   "tourSkip": {
     "message": "ຂ້າມໄປ"
   },
   "tourNext": {
     "message": "ສະໄລດ໌ຕໍ່ໄປ"
   },
   "tourPrevious": {
     "message": "ສະໄລດ໌ກ່ອນຫນ້ານີ້"
   },
   "tourDone": {
     "message": "ສຳເລັດ"
+  },
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "ການນຳໃຊ້ Firefox Screenshots ແມ່ນທ່ານໄດ້ຍອມຮັບເງືອນໄຂການໃຫ້ບໍລິການຂອງ Firefox Cloud Services $TERMSANDPRIVACYNOTICETERMSLINK$ ແລະ $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
+    "placeholders": {
+      "termsandprivacynoticetermslink": {
+        "content": "$1"
+      },
+      "termsandprivacynoticeprivacylink": {
+        "content": "$2"
+      }
+    }
+  },
+  "termsAndPrivacyNoticeTermsLink": {
+    "message": "ຂໍ້ກຳນົດ"
+  },
+  "termsAndPrivacyNoticyPrivacyLink": {
+    "message": "ຄຳເຕືອນກ່ຽວກັບຄວາມເປັນສ່ວນຕົວ"
   }
 }
\ No newline at end of file
--- a/browser/extensions/screenshots/webextension/_locales/lt/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/lt/messages.json
@@ -98,18 +98,18 @@
     "message": "Kita skaidrė"
   },
   "tourPrevious": {
     "message": "Buvusi skaidrė"
   },
   "tourDone": {
     "message": "Baigta"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Naudodamiesi „Firefox Screenshots“, sutinkate su jų $TERMSANDPRIVACYNOTICETERMSLINK$ ir $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Naudodami „Firefox Screenshots“ sutinkate su „Firefox“ tinklo paslaugų $TERMSANDPRIVACYNOTICETERMSLINK$ bei $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/ms/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/ms/messages.json
@@ -97,10 +97,27 @@
   "tourNext": {
     "message": "Slaid Seterusnya"
   },
   "tourPrevious": {
     "message": "Slaid Sebelumnya"
   },
   "tourDone": {
     "message": "Selesai"
+  },
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Dengan menggunakan Firefox Screenshots, anda bersetuju dengan $TERMSANDPRIVACYNOTICETERMSLINK$ dan $TERMSANDPRIVACYNOTICEPRIVACYLINK$ Firefox Cloud Services.",
+    "placeholders": {
+      "termsandprivacynoticetermslink": {
+        "content": "$1"
+      },
+      "termsandprivacynoticeprivacylink": {
+        "content": "$2"
+      }
+    }
+  },
+  "termsAndPrivacyNoticeTermsLink": {
+    "message": "Terma"
+  },
+  "termsAndPrivacyNoticyPrivacyLink": {
+    "message": "Notis Privasi"
   }
 }
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/extensions/screenshots/webextension/_locales/my/messages.json
@@ -0,0 +1,74 @@
+{
+  "addonDescription": {
+    "message": "ဝဘ်ထံမှ ဓါတ်ပုံများနှင့် မျက်နှာပြင်ပုံဖမ်းချက်များကို ရိုက်ယူပြီး ယာယီ သို့မဟုတ် အမြဲတမ်းသိုလှောင်ရာတွင် သိမ်းဆည်းပါ။"
+  },
+  "addonAuthorsList": {
+    "message": "Mozilla <screenshots-feedback@mozilla.org>"
+  },
+  "contextMenuLabel": {
+    "message": "မျက်နှာပြင်ပုံရိပ် ဖမ်းယူပါ"
+  },
+  "myShotsLink": {
+    "message": "ရိုက်ကူးထားသော ပုံများ"
+  },
+  "saveScreenshotSelectedArea": {
+    "message": "သိမ်းရန်"
+  },
+  "saveScreenshotVisibleArea": {
+    "message": "မြင်ရသည်များကို သိမ်းပါ"
+  },
+  "saveScreenshotFullPage": {
+    "message": "စာမျက်နှာတစ်ခုလုံးကို သိမ်းပါ"
+  },
+  "cancelScreenshot": {
+    "message": "မဆောင်ရွက်တော့ပါ"
+  },
+  "downloadScreenshot": {
+    "message": "ဆွဲယူရန်"
+  },
+  "notificationLinkCopiedTitle": {
+    "message": "လင့်ခ်ကို ကူယူပြီး"
+  },
+  "requestErrorTitle": {
+    "message": "ပျက်နေသည်"
+  },
+  "requestErrorDetails": {
+    "message": "စိတ်မကောင်းပါ၊ သင်ရိုက်ကူးထားသော ပုံကို မသိမ်းနိုင်ပါ။ နောင်တွင် ပြန်စမ်းကြည့်ပါ။"
+  },
+  "connectionErrorTitle": {
+    "message": "သင်ရိုက်ကူးထားသော မျက်နှာပြင်ပုံရိပ်များထံ မချိတ်ဆက်နိုင်ပါ။"
+  },
+  "unshootablePageErrorTitle": {
+    "message": "ဒီစာမျက်နှာ၏ မျက်နှာပြင်ပုံရိပ်ကို မရိုက်ကူးနိုင်ပါ။"
+  },
+  "tourBodyOne": {
+    "message": "Firefox ကနေ ထွက်ခွာရန် မလိုဘဲ မျက်နှာပြင်ပုံရိပ်များကို ရိုက်ကူး၊ သိမ်းဆည်း၊ မျှဝေပါ။"
+  },
+  "tourHeaderTwo": {
+    "message": "ကိုယ်နှစ်သက်ရာ စာမျက်နှာများကို ဖမ်းယူပါ"
+  },
+  "tourHeaderThree": {
+    "message": "နှစ်သက်သလို"
+  },
+  "tourHeaderFour": {
+    "message": "ဝင်ဒိုးများ သို့မဟုတ် စာမျက်နှာတစ်ခုလုံးကို ဖမ်းယူပါ"
+  },
+  "tourSkip": {
+    "message": "SKIP"
+  },
+  "tourNext": {
+    "message": "နောက်ဆလိုက်"
+  },
+  "tourPrevious": {
+    "message": "အရင်ကဆလိုက်"
+  },
+  "tourDone": {
+    "message": "ပြီးပြီ"
+  },
+  "termsAndPrivacyNoticeTermsLink": {
+    "message": "စကားရပ်များ"
+  },
+  "termsAndPrivacyNoticyPrivacyLink": {
+    "message": "ကိုယ်ရေးကာကွယ်မှု သတိပေးချက်"
+  }
+}
\ No newline at end of file
--- a/browser/extensions/screenshots/webextension/_locales/nb_NO/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/nb_NO/messages.json
@@ -98,18 +98,18 @@
     "message": "Neste slide"
   },
   "tourPrevious": {
     "message": "Forrige slide"
   },
   "tourDone": {
     "message": "Ferdig"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Ved å bruke Firefox Screenshots, godtar du $TERMSANDPRIVACYNOTICETERMSLINK$ og $TERMSANDPRIVACYNOTICEPRIVACYLINK$ for Screenshots.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Ved å bruke Firefox Screenshots, godtar du $TERMSANDPRIVACYNOTICETERMSLINK$ og $TERMSANDPRIVACYNOTICEPRIVACYLINK$ for Firefox Cloud Services.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/nl/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/nl/messages.json
@@ -98,18 +98,18 @@
     "message": "Volgende slide"
   },
   "tourPrevious": {
     "message": "Vorige slide"
   },
   "tourDone": {
     "message": "Gereed"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Door Firefox Screenshots te gebruiken, gaat u akkoord met de $TERMSANDPRIVACYNOTICETERMSLINK$ en $TERMSANDPRIVACYNOTICEPRIVACYLINK$ van Screenshots.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Door Firefox Screenshots te gebruiken, gaat u akkoord met de $TERMSANDPRIVACYNOTICETERMSLINK$ en $TERMSANDPRIVACYNOTICEPRIVACYLINK$ van Firefox-cloudservices.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/nn_NO/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/nn_NO/messages.json
@@ -98,18 +98,18 @@
     "message": "Neste slide"
   },
   "tourPrevious": {
     "message": "Føregåande slide"
   },
   "tourDone": {
     "message": "Ferdig"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Ved å bruke Firefox Screenshots, godtar du $TERMSANDPRIVACYNOTICETERMSLINK$ og $TERMSANDPRIVACYNOTICEPRIVACYLINK$ for Screenshots.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Ved å bruke Firefox Screenshots, godtar du $TERMSANDPRIVACYNOTICETERMSLINK$ og $TERMSANDPRIVACYNOTICEPRIVACYLINK$ for Firefox Cloud Services.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/pl/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/pl/messages.json
@@ -98,26 +98,26 @@
     "message": "Dalej"
   },
   "tourPrevious": {
     "message": "Wstecz"
   },
   "tourDone": {
     "message": "Zamknij"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Używając Firefox Screenshots, zgadzasz się na $TERMSANDPRIVACYNOTICETERMSLINK$ i $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Używając Firefox Screenshots, zgadzasz się na $TERMSANDPRIVACYNOTICETERMSLINK$ i $TERMSANDPRIVACYNOTICEPRIVACYLINK$ usług Firefox Cloud.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
   },
   "termsAndPrivacyNoticeTermsLink": {
-    "message": "warunki korzystania z usługi"
+    "message": "warunki korzystania"
   },
   "termsAndPrivacyNoticyPrivacyLink": {
     "message": "zasady ochrony prywatności"
   }
 }
\ No newline at end of file
--- a/browser/extensions/screenshots/webextension/_locales/pt_BR/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/pt_BR/messages.json
@@ -98,18 +98,18 @@
     "message": "Próximo slide"
   },
   "tourPrevious": {
     "message": "Slide anterior"
   },
   "tourDone": {
     "message": "Concluir"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Usando Firefox Screenshots, você concorda com os $TERMSANDPRIVACYNOTICETERMSLINK$ e $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Usando o Firefox Screenshots, você concorda com os $TERMSANDPRIVACYNOTICETERMSLINK$ e $TERMSANDPRIVACYNOTICEPRIVACYLINK$ dos serviços na nuvem do Firefox .",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/pt_PT/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/pt_PT/messages.json
@@ -98,18 +98,18 @@
     "message": "Diapositivo seguinte"
   },
   "tourPrevious": {
     "message": "Diapositivo anterior"
   },
   "tourDone": {
     "message": "Feito"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Ao utilizar o Firefox Screenshots, você concorda com os $TERMSANDPRIVACYNOTICETERMSLINK$ e com a $TERMSANDPRIVACYNOTICEPRIVACYLINK$ do Screenshots.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Ao utilizar as Capturas de ecrã Firefox, você concorda com os $TERMSANDPRIVACYNOTICETERMSLINK$ e a $TERMSANDPRIVACYNOTICEPRIVACYLINK$ do Firefox Cloud Services.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/rm/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/rm/messages.json
@@ -98,18 +98,18 @@
     "message": "Proxim pass"
   },
   "tourPrevious": {
     "message": "Ultim pass"
   },
   "tourDone": {
     "message": "Finì"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Cun utilisar Firefox Screenshots accepteschas ti $TERMSANDPRIVACYNOTICETERMSLINK$ e $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Cun utilisar Firefox Screenshots accepteschas ti $TERMSANDPRIVACYNOTICETERMSLINK$ e $TERMSANDPRIVACYNOTICEPRIVACYLINK$ da Firefox Cloud Services.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
new file mode 100644
--- /dev/null
+++ b/browser/extensions/screenshots/webextension/_locales/ro/messages.json
@@ -0,0 +1,38 @@
+{
+  "addonDescription": {
+    "message": "Realizează decupaje și capturi de ecran de pe web și salvează-le temporar sau permanent."
+  },
+  "contextMenuLabel": {
+    "message": "Realizează o captură de ecran"
+  },
+  "myShotsLink": {
+    "message": "Capturile mele"
+  },
+  "saveScreenshotSelectedArea": {
+    "message": "Salvează"
+  },
+  "cancelScreenshot": {
+    "message": "Renunță"
+  },
+  "downloadScreenshot": {
+    "message": "Descarcă"
+  },
+  "notificationLinkCopiedTitle": {
+    "message": "Link copiat"
+  },
+  "tourSkip": {
+    "message": "OMITE"
+  },
+  "tourNext": {
+    "message": "Diapozitivul următor"
+  },
+  "tourPrevious": {
+    "message": "Diapozitivul anterior"
+  },
+  "termsAndPrivacyNoticeTermsLink": {
+    "message": "Termenii"
+  },
+  "termsAndPrivacyNoticyPrivacyLink": {
+    "message": "Politica de confidenţialitate"
+  }
+}
\ No newline at end of file
--- a/browser/extensions/screenshots/webextension/_locales/ru/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/ru/messages.json
@@ -98,18 +98,18 @@
     "message": "Следующий слайд"
   },
   "tourPrevious": {
     "message": "Предыдущий слайд"
   },
   "tourDone": {
     "message": "Готово"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Используя Firefox Screenshots, вы соглашаетесь с его $TERMSANDPRIVACYNOTICETERMSLINK$ и $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Используя Скриншоты Firefox, вы соглашаетесь с $TERMSANDPRIVACYNOTICETERMSLINK$ и $TERMSANDPRIVACYNOTICEPRIVACYLINK$ облачных сервисов Firefox.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/sk/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/sk/messages.json
@@ -98,18 +98,18 @@
     "message": "Ďalšia snímka"
   },
   "tourPrevious": {
     "message": "Predchádzajúca snímka"
   },
   "tourDone": {
     "message": "Hotovo"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Používaním služby Firefox Screenshots vyjadrujete súhlas s $TERMSANDPRIVACYNOTICETERMSLINK$ služby Screenshots a so $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Používaním služby Firefox Screenshots súhlasíte s $TERMSANDPRIVACYNOTICETERMSLINK$ a $TERMSANDPRIVACYNOTICEPRIVACYLINK$ Firefox Cloud Services.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/sl/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/sl/messages.json
@@ -98,18 +98,18 @@
     "message": "Naslednji diapozitiv"
   },
   "tourPrevious": {
     "message": "Prejšnji diapozitiv"
   },
   "tourDone": {
     "message": "Končano"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Z uporabo razširitve Firefox Screenshots se strinjate s $TERMSANDPRIVACYNOTICETERMSLINK$ in $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Z uporabo Firefox Screenshots se strinjate s $TERMSANDPRIVACYNOTICETERMSLINK$ Firefoxovih storitev v oblaku in $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/sq/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/sq/messages.json
@@ -1,14 +1,56 @@
 {
+  "addonAuthorsList": {
+    "message": "Mozilla <screenshots-feedback@mozilla.org>"
+  },
+  "contextMenuLabel": {
+    "message": "Bëni një Foto"
+  },
+  "myShotsLink": {
+    "message": "Shkrepjet e Mia"
+  },
   "saveScreenshotSelectedArea": {
     "message": "Ruaje"
   },
+  "saveScreenshotVisibleArea": {
+    "message": "Ruaj pjesën e dukshme"
+  },
+  "saveScreenshotFullPage": {
+    "message": "Ruaj krejt faqen"
+  },
   "cancelScreenshot": {
     "message": "Anuloje"
   },
   "downloadScreenshot": {
     "message": "Shkarkoje"
   },
   "notificationLinkCopiedTitle": {
     "message": "Lidhja u Kopjua"
+  },
+  "requestErrorDetails": {
+    "message": "Na ndjeni! S’e ruajtëm dot foton tuaj. Ju lutemi, riprovoni më vonë."
+  },
+  "connectionErrorTitle": {
+    "message": "S’lidhemi dot te fotot tuaja."
+  },
+  "unshootablePageErrorTitle": {
+    "message": "S’bëjmë dot foto të kësaj faqeje."
+  },
+  "tourHeaderTwo": {
+    "message": "Fiksoni Në Foto Aq Sa Doni"
+  },
+  "tourHeaderThree": {
+    "message": "Si T’ju Pëlqejë"
+  },
+  "tourHeaderFour": {
+    "message": "Fiksoni Dritare ose Krejt Faqet"
+  },
+  "tourDone": {
+    "message": "U bë"
+  },
+  "termsAndPrivacyNoticeTermsLink": {
+    "message": "Kushte"
+  },
+  "termsAndPrivacyNoticyPrivacyLink": {
+    "message": "Shënim Privatësie"
   }
 }
\ No newline at end of file
--- a/browser/extensions/screenshots/webextension/_locales/sr/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/sr/messages.json
@@ -98,18 +98,18 @@
     "message": "Следећи слајд"
   },
   "tourPrevious": {
     "message": "Претходни слајд"
   },
   "tourDone": {
     "message": "Готово"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Коришћењем услуге Firefox Screenshots, слажете се са $TERMSANDPRIVACYNOTICETERMSLINK$ и $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Коришћењем Firefox Screenshots-а, прихватате Firefox Cloud Services $TERMSANDPRIVACYNOTICETERMSLINK$ и $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/sv_SE/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/sv_SE/messages.json
@@ -98,18 +98,18 @@
     "message": "Nästa sida"
   },
   "tourPrevious": {
     "message": "Föregående sida"
   },
   "tourDone": {
     "message": "Färdig"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Genom att använda Firefox Screenshots, godkänner du $TERMSANDPRIVACYNOTICETERMSLINK$ och $TERMSANDPRIVACYNOTICEPRIVACYLINK$ för Screenshots.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Genom att använda Firefox Screenshots, godkänner du $TERMSANDPRIVACYNOTICETERMSLINK$ och $TERMSANDPRIVACYNOTICEPRIVACYLINK$ för Firefox molntjänster.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
new file mode 100644
--- /dev/null
+++ b/browser/extensions/screenshots/webextension/_locales/te/messages.json
@@ -0,0 +1,50 @@
+{
+  "addonAuthorsList": {
+    "message": "Mozilla <screenshots-feedback@mozilla.org>"
+  },
+  "contextMenuLabel": {
+    "message": "ఒక తెరపట్టు తీసుకోండి"
+  },
+  "myShotsLink": {
+    "message": "నా షాట్లు"
+  },
+  "saveScreenshotSelectedArea": {
+    "message": "భద్రపరచు"
+  },
+  "saveScreenshotFullPage": {
+    "message": "పూర్తి పేజీని భద్రపరచు"
+  },
+  "cancelScreenshot": {
+    "message": "రద్దుచేయి"
+  },
+  "downloadScreenshot": {
+    "message": "దింపుకోండి"
+  },
+  "notificationLinkCopiedTitle": {
+    "message": "లంకె కాపీ అయింది"
+  },
+  "requestErrorDetails": {
+    "message": "క్షమిచండి! మీ తెరను భద్రపరచలేకపోయాం. దయచేసి కాసేపాగి మళ్ళీ ప్రయత్నించండి."
+  },
+  "tourHeaderThree": {
+    "message": "మీకు నచ్చినట్టుగా"
+  },
+  "tourSkip": {
+    "message": "దాటవేయి"
+  },
+  "tourNext": {
+    "message": "తర్వాతి ఫలకం"
+  },
+  "tourPrevious": {
+    "message": "మునుపటి ఫలకం"
+  },
+  "tourDone": {
+    "message": "పూర్తయింది"
+  },
+  "termsAndPrivacyNoticeTermsLink": {
+    "message": "నియమాలు"
+  },
+  "termsAndPrivacyNoticyPrivacyLink": {
+    "message": "అంతరంగికత గమనిక"
+  }
+}
\ No newline at end of file
--- a/browser/extensions/screenshots/webextension/_locales/th/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/th/messages.json
@@ -98,18 +98,18 @@
     "message": "ภาพนิ่งถัดไป"
   },
   "tourPrevious": {
     "message": "ภาพนิ่งก่อนหน้า"
   },
   "tourDone": {
     "message": "เสร็จสิ้น"
   },
-  "termsAndPrivacyNotice": {
-    "message": "เพื่อใช้  Firefox Screenshots คุณยอมรับ $TERMSANDPRIVACYNOTICETERMSLINK$ และ $TERMSANDPRIVACYNOTICEPRIVACYLINK$ ของ Screenshots",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "สำหรับการใช้งาน Firefox Screenshots คุณยอมรับใน Firefox Cloud Services $TERMSANDPRIVACYNOTICETERMSLINK$ และ $TERMSANDPRIVACYNOTICEPRIVACYLINK$",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/tl/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/tl/messages.json
@@ -98,18 +98,18 @@
     "message": "Susunod na Slide"
   },
   "tourPrevious": {
     "message": "Nakaraan na Slide"
   },
   "tourDone": {
     "message": "Tapos"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Sa pamamagitan ng paggamit ng Firefox screenshot, sumasang-ayon ka sa mga screenshot $TERMSANDPRIVACYNOTICETERMSLINK$ at $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Sa paggamit ng Firefox Screenshots, tinatanggap mo ang Firefox Cloud Services $TERMSANDPRIVACYNOTICETERMSLINK$ at $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/tr/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/tr/messages.json
@@ -98,18 +98,18 @@
     "message": "Sonraki slayt"
   },
   "tourPrevious": {
     "message": "Önceki slayt"
   },
   "tourDone": {
     "message": "Tamam"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Firefox Screenshots'ı kullandığınızda Screenshosts $TERMSANDPRIVACYNOTICETERMSLINK$ ve $TERMSANDPRIVACYNOTICEPRIVACYLINK$ kabul etmiş sayılırsınız.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Firefox Screenshots'ı kullandığınızda Firefox Bulut Hizmetleri'nin $TERMSANDPRIVACYNOTICETERMSLINK$ ve $TERMSANDPRIVACYNOTICEPRIVACYLINK$ kabul etmiş sayılırsınız.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/uk/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/uk/messages.json
@@ -98,18 +98,18 @@
     "message": "Наступний слайд"
   },
   "tourPrevious": {
     "message": "Попередній слайд"
   },
   "tourDone": {
     "message": "Готово"
   },
-  "termsAndPrivacyNotice": {
-    "message": "Використовуючи Firefox Screenshots, ви погоджуєтеся з його $TERMSANDPRIVACYNOTICETERMSLINK$ та $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "Використовуючи Firefox Screenshots, ви погоджуєтеся з умовами хмарних послуг Firefox: $TERMSANDPRIVACYNOTICETERMSLINK$ та $TERMSANDPRIVACYNOTICEPRIVACYLINK$.",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/ur/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/ur/messages.json
@@ -59,16 +59,19 @@
     "message": "ہم اس صفحہ کی اسکرین شاٹ نہیں کر سکتے۔"
   },
   "unshootablePageErrorDetails": {
     "message": "یہ ایک میعاری صفحہ نہہیں، تو آپ اسکی اسکرین شاٹ نہیں لے سکتے۔"
   },
   "selfScreenshotErrorTitle": {
     "message": "آپ Firefox اسکرین شاٹس صفحے! کی ایک شاٹ نہیں لے سکت"
   },
+  "genericErrorTitle": {
+    "message": "لاجواب! Firefox Screenshots بہت مشہور ہو گیا۔"
+  },
   "genericErrorDetails": {
     "message": "ہمیں یقین نہیں کہ کیا ہوا تھا۔ خیال رکھ کر پھر کوشش کریں یا بھر مختلف صفحہ کی تصویرلیں؟"
   },
   "tourBodyOne": {
     "message": "۔Firefox کو چھوڑے بغیر اسکرینشاٹس لیں، محفوظ کریں اور شیئر کریں۔"
   },
   "tourHeaderTwo": {
     "message": "جو آپ چاہتے ہیں وہ گرفت کریں"
@@ -94,10 +97,27 @@
   "tourNext": {
     "message": "اگلى سلائيڈ"
   },
   "tourPrevious": {
     "message": "پچھلی سلائڈ"
   },
   "tourDone": {
     "message": "ہوگیا"
+  },
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "۔Firefox Screenshots کے استعمال کے ساتھ  آپ Firefox Cloud Services کے $TERMSANDPRIVACYNOTICETERMSLINK$ اور $TERMSANDPRIVACYNOTICEPRIVACYLINK$ کے ساتھ متفق ہیں۔",
+    "placeholders": {
+      "termsandprivacynoticetermslink": {
+        "content": "$1"
+      },
+      "termsandprivacynoticeprivacylink": {
+        "content": "$2"
+      }
+    }
+  },
+  "termsAndPrivacyNoticeTermsLink": {
+    "message": "شرائط"
+  },
+  "termsAndPrivacyNoticyPrivacyLink": {
+    "message": "اطلاع نامہ نجی نوعیت"
   }
 }
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/extensions/screenshots/webextension/_locales/uz/messages.json
@@ -0,0 +1,64 @@
+{
+  "addonAuthorsList": {
+    "message": "Mozilla <screenshots-feedback@mozilla.org>"
+  },
+  "contextMenuLabel": {
+    "message": "Rasmini olish"
+  },
+  "myShotsLink": {
+    "message": "Rasmlarim"
+  },
+  "screenshotInstructions": {
+    "message": "Hududni belgilash uchun sahifa ustiga tashlang yoki bosing. Chiqish uchun “ESC” tugmasidan foydalaning."
+  },
+  "saveScreenshotSelectedArea": {
+    "message": "Saqlash"
+  },
+  "saveScreenshotVisibleArea": {
+    "message": "Ko‘rinadiganini saqlash"
+  },
+  "saveScreenshotFullPage": {
+    "message": "To‘liq sahifani saqlash"
+  },
+  "cancelScreenshot": {
+    "message": "Bekor qilish"
+  },
+  "downloadScreenshot": {
+    "message": "Yuklab olish"
+  },
+  "notificationLinkCopiedTitle": {
+    "message": "Havoladan nusxa olindi"
+  },
+  "notificationLinkCopiedDetails": {
+    "message": "Rasm havolasidan maxsus xotiraga nusxa olindi. Qo‘yish uchun $META_KEY$-V tugmalarini bosing.",
+    "placeholders": {
+      "meta_key": {
+        "content": "$1"
+      }
+    }
+  },
+  "requestErrorTitle": {
+    "message": "Xizmat hozircha ishlamayapti"
+  },
+  "requestErrorDetails": {
+    "message": "Uzr! Rasmni saqlay olmaymiz. Keyinroq urinib ko‘ring."
+  },
+  "connectionErrorTitle": {
+    "message": "Ekran rasmiga ulana olmadik."
+  },
+  "connectionErrorDetails": {
+    "message": "Internetga ulanishni tekshiring. Ulana olsangiz, demak Firefox Screenshot xizmatida vaqtinchalik muammo bo‘lishi mumkin."
+  },
+  "loginErrorDetails": {
+    "message": "Olingan rasmni saqlay olmaymiz, chunki Firefox Screenshot xizmatida muammo mavjud. Keyinroq urinib ko‘ring."
+  },
+  "unshootablePageErrorTitle": {
+    "message": "Bu sahifani rasmga tushira olmaymiz."
+  },
+  "unshootablePageErrorDetails": {
+    "message": "Bu sahifa standart sahifa emas, shuning uchun uni rasmga tushira olmaymiz."
+  },
+  "selfScreenshotErrorTitle": {
+    "message": "Firefox Screenshot sahifasini rasmga tushirish mumkin emas!"
+  }
+}
\ No newline at end of file
--- a/browser/extensions/screenshots/webextension/_locales/zh_CN/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/zh_CN/messages.json
@@ -98,18 +98,18 @@
     "message": "下一页"
   },
   "tourPrevious": {
     "message": "上一页"
   },
   "tourDone": {
     "message": "完成"
   },
-  "termsAndPrivacyNotice": {
-    "message": "使用 Firefox Screenshots 即代表您同意 Screenshots 的$TERMSANDPRIVACYNOTICETERMSLINK$和$TERMSANDPRIVACYNOTICEPRIVACYLINK$。",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "使用 Firefox Screenshots 即代表您同意 Firefox 云服务的$TERMSANDPRIVACYNOTICETERMSLINK$和$TERMSANDPRIVACYNOTICEPRIVACYLINK$。",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/_locales/zh_TW/messages.json
+++ b/browser/extensions/screenshots/webextension/_locales/zh_TW/messages.json
@@ -98,18 +98,18 @@
     "message": "下一頁"
   },
   "tourPrevious": {
     "message": "上一頁"
   },
   "tourDone": {
     "message": "完成"
   },
-  "termsAndPrivacyNotice": {
-    "message": "使用 Firefox Screenshots,代表您同意 Screenshots 的 $TERMSANDPRIVACYNOTICETERMSLINK$ 及 $TERMSANDPRIVACYNOTICEPRIVACYLINK$。",
+  "termsAndPrivacyNoticeCloudServices": {
+    "message": "繼續使用 Firefox Screenshots,代表您同意 Firefox 雲端服務的 $TERMSANDPRIVACYNOTICETERMSLINK$ 以及 $TERMSANDPRIVACYNOTICEPRIVACYLINK$。",
     "placeholders": {
       "termsandprivacynoticetermslink": {
         "content": "$1"
       },
       "termsandprivacynoticeprivacylink": {
         "content": "$2"
       }
     }
--- a/browser/extensions/screenshots/webextension/assertIsTrusted.js
+++ b/browser/extensions/screenshots/webextension/assertIsTrusted.js
@@ -1,20 +1,20 @@
 /** For use with addEventListener, assures that any events have event.isTrusted set to true
       https://developer.mozilla.org/en-US/docs/Web/API/Event/isTrusted
     Should be applied *inside* catcher.watchFunction
 */
 this.assertIsTrusted = function assertIsTrusted(handlerFunction) {
-  return function (event) {
-    if (! event) {
+  return function(event) {
+    if (!event) {
       let exc = new Error("assertIsTrusted did not get an event");
       exc.noPopup = true;
       throw exc;
     }
-    if (! event.isTrusted) {
+    if (!event.isTrusted) {
       let exc = new Error(`Received untrusted event (type: ${event.type})`);
       exc.noPopup = true;
       throw exc;
     }
     return handlerFunction.call(this, event);
   };
 }
 null;
--- a/browser/extensions/screenshots/webextension/background/analytics.js
+++ b/browser/extensions/screenshots/webextension/background/analytics.js
@@ -1,29 +1,29 @@
 /* globals main, auth, catcher, deviceInfo, communication, log */
 
 "use strict";
 
-this.analytics = (function () {
+this.analytics = (function() {
   let exports = {};
 
   let telemetryPrefKnown = false;
   let telemetryPref;
 
-  exports.sendEvent = function (action, label, options) {
+  exports.sendEvent = function(action, label, options) {
     let eventCategory = "addon";
-    if (! telemetryPrefKnown) {
+    if (!telemetryPrefKnown) {
       log.warn("sendEvent called before we were able to refresh");
       return Promise.resolve();
     }
-    if (! telemetryPref) {
+    if (!telemetryPref) {
       log.info(`Cancelled sendEvent ${eventCategory}/${action}/${label || 'none'} ${JSON.stringify(options)}`);
       return Promise.resolve();
     }
-    if (typeof label == "object" && (! options)) {
+    if (typeof label == "object" && (!options)) {
       options = label;
       label = undefined;
     }
     options = options || {};
     let di = deviceInfo();
     return new Promise((resolve, reject) => {
       let url = main.getBackend() + "/event";
       let req = new XMLHttpRequest();
@@ -51,17 +51,17 @@ this.analytics = (function () {
         event: eventCategory,
         action,
         label,
         options
       }));
     });
   };
 
-  exports.refreshTelemetryPref = function () {
+  exports.refreshTelemetryPref = function() {
     return communication.sendToBootstrap("getTelemetryPref").then((result) => {
       telemetryPrefKnown = true;
       if (result === communication.NO_BOOTSTRAP) {
         telemetryPref = true;
       } else {
         telemetryPref = result;
       }
     }, (error) => {
--- a/browser/extensions/screenshots/webextension/background/auth.js
+++ b/browser/extensions/screenshots/webextension/background/auth.js
@@ -1,14 +1,14 @@
 /* globals browser, log */
 /* globals main, makeUuid, deviceInfo, analytics, catcher, buildSettings, communication */
 
 "use strict";
 
-this.auth = (function () {
+this.auth = (function() {
   let exports = {};
 
   let registrationInfo;
   let initialized = false;
   let authHeader = null;
   let sentryPublicDSN = null;
   let abTests = {};
 
@@ -20,17 +20,17 @@ this.auth = (function () {
       registrationInfo = result.registrationInfo;
     } else {
       registrationInfo = generateRegistrationInfo();
       log.info("Generating new device authentication ID", registrationInfo);
       return browser.storage.local.set({registrationInfo});
     }
   }));
 
-  exports.getDeviceId = function () {
+  exports.getDeviceId = function() {
     return registrationInfo && registrationInfo.deviceId;
   };
 
   function generateRegistrationInfo() {
     let info = {
       deviceId: `anon${makeUuid()}`,
       secret: makeUuid(),
       registered: false
@@ -141,49 +141,48 @@ this.auth = (function () {
       }
     }
     if (responseJson.abTests) {
       abTests = responseJson.abTests;
       catcher.watchPromise(browser.storage.local.set({abTests}));
     }
   }
 
-  exports.getDeviceId = function () {
+  exports.getDeviceId = function() {
     return registrationInfo.deviceId;
   };
 
-  exports.authHeaders = function () {
+  exports.authHeaders = function() {
     let initPromise = Promise.resolve();
-    if (! initialized) {
+    if (!initialized) {
       initPromise = login();
     }
     return initPromise.then(() => {
       if (authHeader) {
         return {"x-screenshots-auth": authHeader};
-      } else {
-        log.warn("No auth header available");
-        return {};
       }
+      log.warn("No auth header available");
+      return {};
     });
   };
 
-  exports.getSentryPublicDSN = function () {
+  exports.getSentryPublicDSN = function() {
     return sentryPublicDSN || buildSettings.defaultSentryDsn;
   };
 
-  exports.getAbTests = function () {
+  exports.getAbTests = function() {
     return abTests;
   };
 
-  exports.isRegistered = function () {
+  exports.isRegistered = function() {
     return registrationInfo.registered;
   };
 
-  exports.setDeviceInfoFromOldAddon = function (newDeviceInfo) {
-    if (! (newDeviceInfo.deviceId && newDeviceInfo.secret)) {
+  exports.setDeviceInfoFromOldAddon = function(newDeviceInfo) {
+    if (!(newDeviceInfo.deviceId && newDeviceInfo.secret)) {
       throw new Error("Bad deviceInfo");
     }
     if (registrationInfo.deviceId === newDeviceInfo.deviceId &&
       registrationInfo.secret === newDeviceInfo.secret) {
       // Probably we already imported the information
       return Promise.resolve(false);
     }
     registrationInfo = {
@@ -194,23 +193,18 @@ this.auth = (function () {
     initialized = false;
     return browser.storage.local.set({registrationInfo}).then(() => {
       return true;
     });
   };
 
   communication.register("getAuthInfo", (sender, ownershipCheck) => {
     let info = registrationInfo;
-    let done = Promise.resolve();
     if (info.registered) {
-      done = login({ownershipCheck}).then((result) => {
-        if (result && result.isOwner) {
-          info.isOwner = true;
-        }
+      return login({ownershipCheck}).then((result) => {
+        return {isOwner: result && result.isOwner, deviceId: registrationInfo.deviceId};
       });
     }
-    return done.then(() => {
-      return info;
-    });
+    return Promise.resolve(info);
   });
 
   return exports;
 })();
--- a/browser/extensions/screenshots/webextension/background/communication.js
+++ b/browser/extensions/screenshots/webextension/background/communication.js
@@ -1,80 +1,78 @@
 /* globals browser, catcher, log */
 
 "use strict";
 
-this.communication = (function () {
+this.communication = (function() {
   let exports = {};
 
   let registeredFunctions = {};
 
   browser.runtime.onMessage.addListener(catcher.watchFunction((req, sender, sendResponse) => {
-    if (! (req.funcName in registeredFunctions)) {
+    if (!(req.funcName in registeredFunctions)) {
       log.error(`Received unknown internal message type ${req.funcName}`);
       sendResponse({type: "error", name: "Unknown message type"});
       return;
     }
-    if (! Array.isArray(req.args)) {
+    if (!Array.isArray(req.args)) {
       log.error("Received message with no .args list");
       sendResponse({type: "error", name: "No .args"});
       return;
     }
     let func = registeredFunctions[req.funcName];
     let result;
     try {
       req.args.unshift(sender);
       result = func.apply(null, req.args);
     } catch (e) {
       log.error(`Error in ${req.funcName}:`, e, e.stack);
       // FIXME: should consider using makeError from catcher here:
-      sendResponse({type: "error", message: e+""});
+      sendResponse({type: "error", message: e + "", errorCode: e.errorCode, popupMessage: e.popupMessage});
       return;
     }
     if (result && result.then) {
       result.then((concreteResult) => {
         sendResponse({type: "success", value: concreteResult});
       }).catch((errorResult) => {
         log.error(`Promise error in ${req.funcName}:`, errorResult, errorResult && errorResult.stack);
-        sendResponse({type: "error", message: errorResult+""});
+        sendResponse({type: "error", message: errorResult + "", errorCode: errorResult.errorCode, popupMessage: errorResult.popupMessage});
       });
       return true;
-    } else {
-      sendResponse({type: "success", value: result});
     }
+    sendResponse({type: "success", value: result});
   }));
 
-  exports.register = function (name, func) {
+  exports.register = function(name, func) {
     registeredFunctions[name] = func;
   };
 
   /** Send a message to bootstrap.js
       Technically any worker can listen to this.  If the bootstrap wrapper is not in place, then this
       will *not* fail, and will return a value of exports.NO_BOOTSTRAP  */
-  exports.sendToBootstrap = function (funcName, ...args) {
+  exports.sendToBootstrap = function(funcName, ...args) {
     return browser.runtime.sendMessage({funcName, args}).then((result) => {
       if (result.type === "success") {
         return result.value;
-      } else {
-        throw new Error(`Error in ${funcName}: ${result.name || 'unknown'}`);
       }
+      throw new Error(`Error in ${funcName}: ${result.name || 'unknown'}`);
     }, (error) => {
       if (isBootstrapMissingError(error)) {
         return exports.NO_BOOTSTRAP;
       }
       throw error;
     });
   };
 
   function isBootstrapMissingError(error) {
-    if (! error) {
+    if (!error) {
       return false;
     }
-    return error.errorCode === "NO_RECEIVING_END" ||
-      (! error.errorCode && error.message === "Could not establish connection. Receiving end does not exist.");
+    return ('errorCode' in error && error.errorCode === "NO_RECEIVING_END") ||
+      (!error.errorCode && error.message === "Could not establish connection. Receiving end does not exist.");
   }
 
 
-  // A singleton/sentinal (with a name):
+  // A singleton/sentinel (with a name):
   exports.NO_BOOTSTRAP = {name: "communication.NO_BOOTSTRAP"};
 
   return exports;
 })();
--- a/browser/extensions/screenshots/webextension/background/deviceInfo.js
+++ b/browser/extensions/screenshots/webextension/background/deviceInfo.js
@@ -1,13 +1,13 @@
 /* globals browser, catcher */
 
 "use strict";
 
-this.deviceInfo = (function () {
+this.deviceInfo = (function() {
   let manifest = browser.runtime.getManifest();
 
   let platformInfo = {};
   catcher.watchPromise(browser.runtime.getPlatformInfo().then((info) => {
     platformInfo = info;
   }));
 
   return function deviceInfo() {
@@ -18,17 +18,17 @@ this.deviceInfo = (function () {
     let appName = chromeVersion ? "chrome" : "firefox";
 
     return {
       addonVersion: manifest.version,
       platform: platformInfo.os,
       architecture: platformInfo.arch,
       version: firefoxVersion || chromeVersion,
       // These don't seem to apply to Chrome:
-      //build: system.build,
-      //platformVersion: system.platformVersion,
+      // build: system.build,
+      // platformVersion: system.platformVersion,
       userAgent: navigator.userAgent,
       appVendor: appName,
       appName
     };
   };
 
 })();
--- a/browser/extensions/screenshots/webextension/background/main.js
+++ b/browser/extensions/screenshots/webextension/background/main.js
@@ -1,43 +1,43 @@
-/* globals browser, console, XMLHttpRequest, Image, document, setTimeout, navigator */
-/* globals selectorLoader, analytics, communication, catcher, makeUuid, auth, senderror */
+/* globals browser, XMLHttpRequest, Image, document, setTimeout, navigator */
+/* globals selectorLoader, analytics, communication, catcher, log, makeUuid, auth, senderror */
 
 "use strict";
 
-this.main = (function () {
+this.main = (function() {
   let exports = {};
 
   const pasteSymbol = (window.navigator.platform.match(/Mac/i)) ? "\u2318" : "Ctrl";
   const { sendEvent } = analytics;
 
   let manifest = browser.runtime.getManifest();
   let backend;
 
   let hasSeenOnboarding;
 
   browser.storage.local.get(["hasSeenOnboarding"]).then((result) => {
-    hasSeenOnboarding = !! result.hasSeenOnboarding;
-    if (! hasSeenOnboarding) {
+    hasSeenOnboarding = !!result.hasSeenOnboarding;
+    if (!hasSeenOnboarding) {
       setIconActive(false, null);
       // Note that the branded name 'Firefox Screenshots' is not localized:
       browser.browserAction.setTitle({
         title: "Firefox Screenshots"
       });
     }
   }).catch((error) => {
     log.error("Error getting hasSeenOnboarding:", error);
   });
 
-  exports.setBackend = function (newBackend) {
+  exports.setBackend = function(newBackend) {
     backend = newBackend;
     backend = backend.replace(/\/*$/, "");
   };
 
-  exports.getBackend = function () {
+  exports.getBackend = function() {
     return backend;
   };
 
   communication.register("getBackend", () => {
     return backend;
   });
 
   function getOnboardingUrl() {
@@ -47,19 +47,19 @@ this.main = (function () {
   for (let permission of manifest.permissions) {
     if (/^https?:\/\//.test(permission)) {
       exports.setBackend(permission);
       break;
     }
   }
 
   function setIconActive(active, tabId) {
-    let path = active ? "icons/icon-highlight-38.png" : "icons/icon-38.png";
-    if ((! hasSeenOnboarding) && ! active) {
-      path = "icons/icon-starred-38.png";
+    let path = active ? "icons/icon-highlight-32.svg" : "icons/icon-32.svg";
+    if ((!hasSeenOnboarding) && !active) {
+      path = "icons/icon-starred-32.svg";
     }
     browser.browserAction.setIcon({path, tabId});
   }
 
   function toggleSelector(tab) {
     return analytics.refreshTelemetryPref()
       .then(() => selectorLoader.toggle(tab.id, hasSeenOnboarding))
       .then(active => {
@@ -67,23 +67,35 @@ this.main = (function () {
         return active;
       })
       .catch((error) => {
         error.popupMessage = "UNSHOOTABLE_PAGE";
         throw error;
       });
   }
 
+  function startSelectionWithOnboarding(tab) {
+    return analytics.refreshTelemetryPref().then(() => {
+      return selectorLoader.testIfLoaded(tab.id);
+    }).then((isLoaded) => {
+      if (!isLoaded) {
+        sendEvent("start-shot", "site-request");
+        setIconActive(true, tab.id);
+        selectorLoader.toggle(tab.id, false);
+      }
+    });
+  }
+
   function shouldOpenMyShots(url) {
     return /^about:(?:newtab|blank)/i.test(url) || /^resource:\/\/activity-streams\//i.test(url);
   }
 
   browser.browserAction.onClicked.addListener(catcher.watchFunction((tab) => {
     if (shouldOpenMyShots(tab.url)) {
-      if (! hasSeenOnboarding) {
+      if (!hasSeenOnboarding) {
         catcher.watchPromise(analytics.refreshTelemetryPref().then(() => {
           sendEvent("goto-onboarding", "selection-button");
           return forceOnboarding();
         }));
         return;
       }
       catcher.watchPromise(analytics.refreshTelemetryPref().then(() => {
         sendEvent("goto-myshots", "about-newtab");
@@ -93,17 +105,17 @@ this.main = (function () {
         .then(() => browser.tabs.update({url: backend + "/shots"})));
     } else {
       catcher.watchPromise(
         toggleSelector(tab)
           .then(active => {
             const event = active ? "start-shot" : "cancel-shot";
             sendEvent(event, "toolbar-button");
           }, (error) => {
-            if ((! hasSeenOnboarding) && error.popupMessage == "UNSHOOTABLE_PAGE") {
+            if ((!hasSeenOnboarding) && error.popupMessage == "UNSHOOTABLE_PAGE") {
               sendEvent("goto-onboarding", "selection-button");
               return forceOnboarding();
             }
             throw error;
           }));
     }
   }));
 
@@ -121,17 +133,17 @@ this.main = (function () {
   }, () => {
     // Note: unlike most browser.* functions this one does not return a promise
     if (browser.runtime.lastError) {
       catcher.unhandled(new Error(browser.runtime.lastError.message));
     }
   });
 
   browser.contextMenus.onClicked.addListener(catcher.watchFunction((info, tab) => {
-    if (! tab) {
+    if (!tab) {
       // Not in a page/tab context, ignore
       return;
     }
     catcher.watchPromise(
       toggleSelector(tab)
         .then(() => sendEvent("start-shot", "context-menu")));
   }));
 
@@ -142,24 +154,24 @@ this.main = (function () {
     if (isShotOrMyShotPage(url) || /^(?:about|data|moz-extension):/i.test(url) || isBlacklistedUrl(url)) {
       return false;
     }
     return true;
   }
 
   function isShotOrMyShotPage(url) {
     // It's okay to take a shot of any pages except shot pages and My Shots
-    if (! url.startsWith(backend)) {
+    if (!url.startsWith(backend)) {
       return false;
     }
-    let path = url.substr(backend.length).replace(/^\/*/, "").replace(/#.*/, "").replace(/\?.*/, "");
+    let path = url.substr(backend.length).replace(/^\/*/, "").replace(/[?#].*/, "");
     if (path == "shots") {
       return true;
     }
-    if (/^[^/]+\/[^/]+$/.test(url)) {
+    if (/^[^/]+\/[^/]+$/.test(path)) {
       // Blocks {:id}/{:domain}, but not /, /privacy, etc
       return true;
     }
     return false;
   }
 
   function isBlacklistedUrl(url) {
     // These specific domains are not allowed for general WebExtension permission reasons
@@ -168,38 +180,51 @@ this.main = (function () {
     // Note we disable it here to be informative, the security check is done in WebExtension code
     const badDomains = ["addons.mozilla.org", "testpilot.firefox.com"];
     let domain = url.replace(/^https?:\/\//i, "");
     domain = domain.replace(/\/.*/, "").replace(/:.*/, "");
     domain = domain.toLowerCase();
     return badDomains.includes(domain);
   }
 
+  function enableButton(tabId) {
+    browser.browserAction.enable(tabId);
+    // We have to manually toggle the icon state, because disabled toolbar
+    // buttons aren't automatically dimmed for WebExtensions on Windows or
+    // Linux (bug 1204609).
+    setIconActive(false, tabId);
+  }
+
+  function disableButton(tabId) {
+    browser.browserAction.disable(tabId);
+    setIconActive(true, tabId);
+  }
+
   browser.tabs.onUpdated.addListener(catcher.watchFunction((id, info, tab) => {
     if (info.url && tab.active) {
       if (urlEnabled(info.url)) {
-        browser.browserAction.enable(tab.id);
+        enableButton(tab.id);
       } else if (hasSeenOnboarding) {
-        browser.browserAction.disable(tab.id);
+        disableButton(tab.id);
       }
     }
-  }));
+  }, true));
 
   browser.tabs.onActivated.addListener(catcher.watchFunction(({tabId, windowId}) => {
     catcher.watchPromise(browser.tabs.get(tabId).then((tab) => {
       // onActivated may fire before the url is set
       if (!tab.url) {
         return;
       }
       if (urlEnabled(tab.url)) {
-        browser.browserAction.enable(tabId);
+        enableButton(tabId);
       } else if (hasSeenOnboarding) {
-        browser.browserAction.disable(tabId);
+        disableButton(tabId);
       }
-    }));
+    }), true);
   }));
 
   communication.register("sendEvent", (sender, ...args) => {
     catcher.watchPromise(sendEvent(...args));
     // We don't wait for it to complete:
     return null;
   });
 
@@ -222,28 +247,42 @@ this.main = (function () {
   });
 
   communication.register("downloadShot", (sender, info) => {
     // 'data:' urls don't work directly, let's use a Blob
     // see http://stackoverflow.com/questions/40269862/save-data-uri-as-file-using-downloads-download-api
     const binary = atob(info.url.split(',')[1]); // just the base64 data
     const data = Uint8Array.from(binary, char => char.charCodeAt(0))
     const blob = new Blob([data], {type: "image/png"})
+    let url = URL.createObjectURL(blob);
+    let downloadId;
+    let onChangedCallback = catcher.watchFunction(function(change) {
+      if (!downloadId || downloadId != change.id) {
+        return;
+      }
+      if (change.state && change.state.current != "in_progress") {
+        URL.revokeObjectURL(url);
+        browser.downloads.onChanged.removeListener(onChangedCallback);
+      }
+    });
+    browser.downloads.onChanged.addListener(onChangedCallback)
     return browser.downloads.download({
-      url: URL.createObjectURL(blob),
+      url,
       filename: info.filename
+    }).then((id) => {
+      downloadId = id;
     });
   });
 
   communication.register("closeSelector", (sender) => {
     setIconActive(false, sender.tab.id)
   });
 
   catcher.watchPromise(communication.sendToBootstrap("getOldDeviceInfo").then((deviceInfo) => {
-    if (deviceInfo === communication.NO_BOOTSTRAP || ! deviceInfo) {
+    if (deviceInfo === communication.NO_BOOTSTRAP || !deviceInfo) {
       return;
     }
     deviceInfo = JSON.parse(deviceInfo);
     if (deviceInfo && typeof deviceInfo == "object") {
       return auth.setDeviceInfoFromOldAddon(deviceInfo).then((updated) => {
         if (updated === communication.NO_BOOTSTRAP) {
           throw new Error("bootstrap.js disappeared unexpectedly");
         }
@@ -267,10 +306,25 @@ this.main = (function () {
     sendEvent("abort-start-shot", "frame-page");
     // Note, we only show the error but don't report it, as we know that we can't
     // take shots of these pages:
     senderror.showError({
       popupMessage: "UNSHOOTABLE_PAGE"
     });
   });
 
+  // Note: this signal is only needed until bug 1357589 is fixed.
+  communication.register("openTermsPage", () => {
+    return catcher.watchPromise(browser.tabs.create({url: "https://www.mozilla.org/about/legal/terms/services/"}));
+  });
+
+  // Note: this signal is also only needed until bug 1357589 is fixed.
+  communication.register("openPrivacyPage", () => {
+    return catcher.watchPromise(browser.tabs.create({url: "https://www.mozilla.org/privacy/firefox-cloud/"}));
+  });
+
+  // A Screenshots page wants us to start/force onboarding
+  communication.register("requestOnboarding", (sender) => {
+    return startSelectionWithOnboarding(sender.tab);
+  });
+
   return exports;
 })();
--- a/browser/extensions/screenshots/webextension/background/selectorLoader.js
+++ b/browser/extensions/screenshots/webextension/background/selectorLoader.js
@@ -1,13 +1,15 @@
 /* globals browser, catcher, log */
 
 "use strict";
 
-this.selectorLoader = (function () {
+var global = this;
+
+this.selectorLoader = (function() {
   const exports = {};
 
   // These modules are loaded in order, first standardScripts, then optionally onboardingScripts, and then selectorScripts
   // The order is important due to dependencies
   const standardScripts = [
     "build/buildSettings.js",
     "log.js",
     "catcher.js",
@@ -32,31 +34,54 @@ this.selectorLoader = (function () {
 
   // These are loaded on request (by the selector worker) to activate the onboarding:
   const onboardingScripts = [
     "build/onboardingCss.js",
     "build/onboardingHtml.js",
     "onboarding/slides.js"
   ];
 
-  exports.unloadIfLoaded = function (tabId) {
+  exports.unloadIfLoaded = function(tabId) {
     return browser.tabs.executeScript(tabId, {
       code: "this.selectorLoader && this.selectorLoader.unloadModules()",
       runAt: "document_start"
     }).then(result => {
       return result && result[0];
     });
   };
 
-  exports.loadModules = function (tabId, hasSeenOnboarding) {
+  exports.testIfLoaded = function(tabId) {
+    if (loadingTabs.has(tabId)) {
+      return true;
+    }
+    return browser.tabs.executeScript(tabId, {
+      code: "!!this.selectorLoader",
+      runAt: "document_start"
+    }).then(result => {
+      return result && result[0];
+    });
+  };
+
+  let loadingTabs = new Set();
+
+  exports.loadModules = function(tabId, hasSeenOnboarding) {
+    let promise;
+    loadingTabs.add(tabId);
     if (hasSeenOnboarding) {
-      return executeModules(tabId, standardScripts.concat(selectorScripts));
+      promise = executeModules(tabId, standardScripts.concat(selectorScripts));
     } else {
-      return executeModules(tabId, standardScripts.concat(onboardingScripts).concat(selectorScripts));
+      promise = executeModules(tabId, standardScripts.concat(onboardingScripts).concat(selectorScripts));
     }
+    return promise.then((result) => {
+      loadingTabs.delete(tabId);
+      return result;
+    }, (error) => {
+      loadingTabs.delete(tabId);
+      throw error;
+    });
   };
 
   function executeModules(tabId, scripts) {
     let lastPromise = Promise.resolve(null);
     scripts.forEach((file) => {
       lastPromise = lastPromise.then(() => {
         return browser.tabs.executeScript(tabId, {
           file,
@@ -74,17 +99,17 @@ this.selectorLoader = (function () {
     },
     (error) => {
       exports.unloadIfLoaded(tabId);
       catcher.unhandled(error);
       throw error;
     });
   }
 
-  exports.unloadModules = function () {
+  exports.unloadModules = function() {
     const watchFunction = catcher.watchFunction;
     let allScripts = standardScripts.concat(onboardingScripts).concat(selectorScripts);
     const moduleNames = allScripts.map((filename) =>
       filename.replace(/^.*\//, "").replace(/\.js$/, ""));
     moduleNames.reverse();
     for (let moduleName of moduleNames) {
       let moduleObj = global[moduleName];
       if (moduleObj && moduleObj.unload) {
@@ -94,17 +119,17 @@ this.selectorLoader = (function () {
           // ignore (watchFunction handles it)
         }
       }
       delete global[moduleName];
     }
     return true;
   };
 
-  exports.toggle = function (tabId, hasSeenOnboarding) {
+  exports.toggle = function(tabId, hasSeenOnboarding) {
     return exports.unloadIfLoaded(tabId)
       .then(wasLoaded => {
         if (!wasLoaded) {
           exports.loadModules(tabId, hasSeenOnboarding);
         }
         return !wasLoaded;
       })
   };
--- a/browser/extensions/screenshots/webextension/background/senderror.js
+++ b/browser/extensions/screenshots/webextension/background/senderror.js
@@ -1,15 +1,17 @@
 /* globals analytics, browser, communication, makeUuid, Raven, catcher, auth, log */
 
 "use strict";
 
-this.senderror = (function () {
+this.senderror = (function() {
   let exports = {};
 
+  let manifest = browser.runtime.getManifest();
+
   // Do not show an error more than every ERROR_TIME_LIMIT milliseconds:
   const ERROR_TIME_LIMIT = 3000;
 
   let messages = {
     REQUEST_ERROR: {
       title: browser.i18n.getMessage("requestErrorTitle"),
       info: browser.i18n.getMessage("requestErrorDetails")
     },
@@ -43,24 +45,24 @@ this.senderror = (function () {
   };
 
   communication.register("reportError", (sender, error) => {
     catcher.unhandled(error);
   });
 
   let lastErrorTime;
 
-  exports.showError = function (error) {
+  exports.showError = function(error) {
     if (lastErrorTime && (Date.now() - lastErrorTime) < ERROR_TIME_LIMIT) {
       return;
     }
     lastErrorTime = Date.now();
     let id = makeUuid();
     let popupMessage = error.popupMessage || "generic";
-    if (! messages[popupMessage]) {
+    if (!messages[popupMessage]) {
       popupMessage = "generic";
     }
     let title = messages[popupMessage].title;
     let message = messages[popupMessage].info || '';
     let showMessage = messages[popupMessage].showMessage;
     if (error.message && showMessage) {
       if (message) {
         message += "\n" + error.message;
@@ -71,47 +73,47 @@ this.senderror = (function () {
     browser.notifications.create(id, {
       type: "basic",
       // FIXME: need iconUrl for an image, see #2239
       title,
       message
     });
   };
 
-  exports.reportError = function (e) {
+  exports.reportError = function(e) {
     if (!analytics.getTelemetryPrefSync()) {
       log.error("Telemetry disabled. Not sending critical error:", e);
       return;
     }
     let dsn = auth.getSentryPublicDSN();
-    if (! dsn) {
+    if (!dsn) {
       log.warn("Error:", e);
       return;
     }
-    if (! Raven.isSetup()) {
+    if (!Raven.isSetup()) {
       Raven.config(dsn).install();
     }
     let exception = new Error(e.message);
     exception.stack = e.multilineStack || e.stack || undefined;
     let rest = {};
     for (let attr in e) {
-      if (! ["name", "message", "stack", "multilineStack", "popupMessage", "version", "sentryPublicDSN", "help"].includes(attr)) {
+      if (!["name", "message", "stack", "multilineStack", "popupMessage", "version", "sentryPublicDSN", "help"].includes(attr)) {
         rest[attr] = e[attr];
       }
     }
     rest.stack = e.multilineStack || e.stack;
     Raven.captureException(exception, {
       logger: 'addon',
-      tags: {version: e.version, category: e.popupMessage},
+      tags: {version: manifest.version, category: e.popupMessage},
       message: exception.message,
       extra: rest
     });
   };
 
   catcher.registerHandler((errorObj) => {
-    if (! errorObj.noPopup) {
+    if (!errorObj.noPopup) {
       exports.showError(errorObj);
     }
     exports.reportError(errorObj);
   });
 
   return exports;
 })();
--- a/browser/extensions/screenshots/webextension/background/takeshot.js
+++ b/browser/extensions/screenshots/webextension/background/takeshot.js
@@ -1,23 +1,24 @@
 /* globals communication, shot, main, auth, catcher, analytics, browser */
 
 "use strict";
 
-this.takeshot = (function () {
+this.takeshot = (function() {
   let exports = {};
   const Shot = shot.AbstractShot;
   const { sendEvent } = analytics;
 
   communication.register("takeShot", catcher.watchFunction((sender, options) => {
     let { captureType, captureText, scroll, selectedPos, shotId, shot } = options;
     shot = new Shot(main.getBackend(), shotId, shot);
+    shot.favicon = sender.tab.favIconUrl;
     let capturePromise = Promise.resolve();
     let openedTab;
-    if (! shot.clipNames().length) {
+    if (!shot.clipNames().length) {
       // canvas.drawWindow isn't available, so we fall back to captureVisibleTab
       capturePromise = screenshotPage(selectedPos, scroll).then((dataUrl) => {
         shot.addClip({
           createdDate: Date.now(),
           image: {
             url: dataUrl,
             captureType,
             text: captureText,
@@ -95,34 +96,34 @@ this.takeshot = (function () {
       });
     }));
   }
 
   function uploadShot(shot) {
     return auth.authHeaders().then((headers) => {
       headers["content-type"] = "application/json";
       let body = JSON.stringify(shot.asJson());
-      let req = new Request(shot.jsonUrl, {
+      sendEvent("upload", "started", {eventValue: Math.floor(body.length / 1000)});
+      return fetch(shot.jsonUrl, {
         method: "PUT",
         mode: "cors",
         headers,
         body
       });
-      sendEvent("upload", "started", {eventValue: Math.floor(body.length / 1000)});
-      return fetch(req);
     }).then((resp) => {
-      if (! resp.ok) {
+      if (!resp.ok) {
         sendEvent("upload-failed", `status-${resp.status}`);
         let exc = new Error(`Response failed with status ${resp.status}`);
         exc.popupMessage = "REQUEST_ERROR";
         throw exc;
       } else {
         sendEvent("upload", "success");
       }
     }, (error) => {
       // FIXME: I'm not sure what exceptions we can expect
       sendEvent("upload-failed", "connection");
+      error.popupMessage = "CONNECTION_ERROR";
       throw error;
     });
   }
 
   return exports;
 })();
--- a/browser/extensions/screenshots/webextension/build/buildSettings.js
+++ b/browser/extensions/screenshots/webextension/build/buildSettings.js
@@ -1,6 +1,6 @@
 window.buildSettings = {
-  defaultSentryDsn: "",
+  defaultSentryDsn: "https://97d8afa496f94764ae255e739b147f4b@sentry.prod.mozaws.net/139",
   logLevel: "" || "warn"
 };
 null;
 
--- a/browser/extensions/screenshots/webextension/build/inlineSelectionCss.js
+++ b/browser/extensions/screenshots/webextension/build/inlineSelectionCss.js
@@ -11,96 +11,106 @@ window.inlineSelectionCss = `
   font-weight: 400;
   height: 40px;
   min-width: 40px;
   outline: none;
   padding: 0 10px;
   position: relative;
   text-align: center;
   text-decoration: none;
-  transition: background 150ms;
+  transition: background 150ms cubic-bezier(0.07, 0.95, 0, 1), border 150ms cubic-bezier(0.07, 0.95, 0, 1);
   user-select: none;
   white-space: nowrap; }
   .button.small, .small.highlight-button-cancel, .small.highlight-button-save, .small.highlight-button-download {
     height: 32px;
     line-height: 32px;
     padding: 0 8px; }
   .button.tiny, .tiny.highlight-button-cancel, .tiny.highlight-button-save, .tiny.highlight-button-download {
-    font-size: 12px;
-    height: 22px;
-    line-height: 12px;
-    padding: 2px 6px; }
+    font-size: 14px;
+    height: 26px;
+    border: 1px solid #c7c7c7; }
+    .button.tiny:hover, .tiny.highlight-button-cancel:hover, .tiny.highlight-button-save:hover, .tiny.highlight-button-download:hover, .button.tiny:focus, .tiny.highlight-button-cancel:focus, .tiny.highlight-button-save:focus, .tiny.highlight-button-download:focus {
+      background: #ebebeb;
+      border-color: #989898; }
+    .button.tiny:active, .tiny.highlight-button-cancel:active, .tiny.highlight-button-save:active, .tiny.highlight-button-download:active {
+      background: #dedede;
+      border-color: #989898; }
   .button.set-width--medium, .set-width--medium.highlight-button-cancel, .set-width--medium.highlight-button-save, .set-width--medium.highlight-button-download {
     max-width: 200px; }
-  .button.inline, .inline.highlight-button-cancel, .inline.highlight-button-save, .inline.highlight-button-download {
-    display: inline-block; }
   .button.block-button, .block-button.highlight-button-cancel, .block-button.highlight-button-save, .block-button.highlight-button-download {
     display: flex;
     align-items: center;
     justify-content: center;
+    box-sizing: border-box;
     border: none;
-    border-right: 1px solid rgba(0, 0, 0, 0.1);
+    border-right: 1px solid #c7c7c7;
     box-shadow: none;
     border-radius: 0;
-    height: 100%;
-    line-height: 100%;
-    padding: 0 20px;
-    margin-right: 20px;
-    flex: 0 0 155px; }
-  .button .arrow-icon, .highlight-button-cancel .arrow-icon, .highlight-button-save .arrow-icon, .highlight-button-download .arrow-icon {
-    display: inline-block;
-    position: relative;
-    top: 1px;
-    flex: 0 0 18px;
-    height: 16px;
-    opacity: .6;
-    background-image: url(../img/arrow-page-right-16.svg);
-    background-position: right center;
-    background-repeat: no-repeat; }
+    flex-shrink: 0;
+    font-size: 20px;
+    height: 100px;
+    line-height: 100%; }
+    @media (max-width: 719px) {
+      .button.block-button, .block-button.highlight-button-cancel, .block-button.highlight-button-save, .block-button.highlight-button-download {
+        justify-content: flex-start;
+        padding: 10px;
+        font-size: 16px;
+        height: 72px;
+        flex: 1 0;
+        margin-right: 10px; } }
+    .button.block-button:hover, .block-button.highlight-button-cancel:hover, .block-button.highlight-button-save:hover, .block-button.highlight-button-download:hover {
+      background: #ebebeb; }
+    .button.block-button:active, .block-button.highlight-button-cancel:active, .block-button.highlight-button-save:active, .block-button.highlight-button-download:active {
+      background: #dedede; }
 
 .inverse-color-scheme {
-  background: #383E49;
-  color: #FFF; }
+  background: #3e3d40;
+  color: #f5f5f7; }
   .inverse-color-scheme a {
-    color: #0996F8; }
-  .inverse-color-scheme .large-icon {
-    filter: invert(100%); }
+    color: #e1e1e6; }
 
 .default-color-scheme {
-  background: #f2f2f2;
-  color: #000; }
+  background: #f5f5f7;
+  color: #3e3d40; }
   .default-color-scheme a {
-    color: #0996F8; }
+    color: #009ec0; }
+
+.highlight-color-scheme {
+  background: #009ec0;
+  color: #fff; }
+  .highlight-color-scheme a {
+    color: #fff;
+    text-decoration: underline; }
 
 .button.primary, .primary.highlight-button-cancel, .highlight-button-save, .primary.highlight-button-download {
-  background-color: #0996F8;
-  color: #FFF; }
+  background-color: #009ec0;
+  color: #fff; }
   .button.primary:hover, .primary.highlight-button-cancel:hover, .highlight-button-save:hover, .primary.highlight-button-download:hover, .button.primary:focus, .primary.highlight-button-cancel:focus, .highlight-button-save:focus, .primary.highlight-button-download:focus {
-    background-color: #0681d7; }
+    background-color: #00819c; }
   .button.primary:active, .primary.highlight-button-cancel:active, .highlight-button-save:active, .primary.highlight-button-download:active {
-    background-color: #0573be; }
+    background-color: #006c83; }
 
 .button.secondary, .highlight-button-cancel, .secondary.highlight-button-save, .highlight-button-download {
-  background: #EDEDED;
-  color: #000; }
-  .button.secondary:hover, .highlight-button-cancel:hover, .secondary.highlight-button-save:hover, .highlight-button-download:hover, .button.secondary:focus, .highlight-button-cancel:focus, .secondary.highlight-button-save:focus, .highlight-button-download:focus {
-    background-color: #dbdbdb; }
-  .button.secondary:active, .highlight-button-cancel:active, .secondary.highlight-button-save:active, .highlight-button-download:active {
-    background-color: #cecece; }
+  background-color: #f5f5f7;
+  color: #3e3d40; }
+  .button.secondary:hover, .highlight-button-cancel:hover, .secondary.highlight-button-save:hover, .highlight-button-download:hover {
+    background-color: #ebebeb; }
+  .button.secondary:hover, .highlight-button-cancel:hover, .secondary.highlight-button-save:hover, .highlight-button-download:hover {
+    background-color: #dedede; }
 
 .button.warning, .warning.highlight-button-cancel, .warning.highlight-button-save, .warning.highlight-button-download {
-  color: #FFF;
+  color: #fff;
   background: #d92215; }
   .button.warning:hover, .warning.highlight-button-cancel:hover, .warning.highlight-button-save:hover, .warning.highlight-button-download:hover, .button.warning:focus, .warning.highlight-button-cancel:focus, .warning.highlight-button-save:focus, .warning.highlight-button-download:focus {
     background: #b81d12; }
   .button.warning:active, .warning.highlight-button-cancel:active, .warning.highlight-button-save:active, .warning.highlight-button-download:active {
     background: #a11910; }
 
 .subtitle-link {
-  color: #0996F8; }
+  color: #009ec0; }
 
 @keyframes fade-in {
   0% {
     opacity: 0; }
   100% {
     opacity: 1; } }
 
 @keyframes pop {
@@ -214,17 +224,17 @@ window.inlineSelectionCss = `
   height: 60px;
   right: -30px;
   width: 60px; }
 
 .mover-target:hover .mover {
   transform: scale(1.05); }
 
 .mover {
-  background-color: #FFF;
+  background-color: #fff;
   border-radius: 50%;
   box-shadow: 0 0 4px rgba(0, 0, 0, 0.5);
   height: 16px;
   opacity: 1;
   position: relative;
   transition: transform 125ms cubic-bezier(0.07, 0.95, 0, 1);
   width: 16px; }
   .small-selection .mover {
@@ -283,50 +293,42 @@ window.inlineSelectionCss = `
   align-items: center;
   justify-content: center;
   bottom: -55px;
   position: absolute;
   right: 5px;
   z-index: 6; }
   .bottom-selection .highlight-buttons {
     bottom: 5px; }
+  .left-selection .highlight-buttons {
+    right: auto;
+    left: 5px; }
 
 .highlight-button-cancel {
-  background-color: #ededed;
   background-image: url("MOZ_EXTENSION/icons/cancel.svg");
   background-position: center center;
   background-repeat: no-repeat;
   background-size: 18px 18px;
   margin: 5px;
   width: 40px; }
 
 .highlight-button-save {
   font-size: 18px;
   margin: 5px;
   min-width: 80px; }
 
 .highlight-button-download {
-  background-color: #ededed;
   background-image: url("MOZ_EXTENSION/icons/download.svg");
   background-position: center center;
   background-repeat: no-repeat;
   background-size: 18px 18px;
   display: block;
   margin: 5px;
   width: 40px; }
 
-.highlight-button-cancel,
-.highlight-button-download {
-  transition: background-color cubic-bezier(0.07, 0.95, 0, 1) 250ms; }
-  .highlight-button-cancel:hover, .highlight-button-cancel:focus, .highlight-button-cancel:active,
-  .highlight-button-download:hover,
-  .highlight-button-download:focus,
-  .highlight-button-download:active {
-    background-color: #dbdbdb; }
-
 .pixel-dimensions {
   position: absolute;
   pointer-events: none;
   font-weight: bold;
   font-family: sans-serif;
   font-size: 70%;
   color: #000;
   text-shadow: -1px -1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff, 1px 1px 0 #fff; }
@@ -339,27 +341,71 @@ window.inlineSelectionCss = `
   left: 0;
   margin: 0;
   padding: 0;
   pointer-events: none;
   position: absolute;
   top: 0;
   width: 100%; }
 
+.face-container {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  margin: auto;
+  width: 64px;
+  height: 64px;
+  transform: translateY(-45px); }
+
+.eye {
+  background-color: #fff;
+  width: 10.8px;
+  height: 14.6px;
+  position: absolute;
+  border-radius: 100%;
+  overflow: hidden;
+  left: 16.4px;
+  top: 19.8px; }
+
+.eyeball {
+  position: absolute;
+  width: 6px;
+  height: 6px;
+  background-color: #000;
+  border-radius: 50%;
+  left: 2.4px;
+  top: 4.3px;
+  z-index: 10; }
+
+.left {
+  margin-left: 0; }
+
+.right {
+  margin-left: 20px; }
+
+.face {
+  width: 62.4px;
+  height: 62.4px;
+  display: block;
+  background-image: url("MOZ_EXTENSION/icons/icon-welcome-face-without-eyes.svg"); }
+
 .preview-instructions {
   display: flex;
   align-items: center;
   justify-content: center;
   animation: pulse 125mm cubic-bezier(0.07, 0.95, 0, 1);
   color: #fff;
   font-family: -apple-system, BlinkMacSystemFont, sans-serif;
   font-size: 24px;
   line-height: 32px;
   text-align: center;
-  width: 400px; }
+  width: 400px;
+  margin-top: 45px; }
 
 .myshots-all-buttons-container {
   display: flex;
   flex-direction: row-reverse;
   background: #f5f5f5;
   border-radius: 1px;
   box-sizing: border-box;
   height: 80px;
@@ -407,17 +453,17 @@ window.inlineSelectionCss = `
 .myshots-button-container {
   display: flex;
   align-items: center;
   justify-content: center; }
 
 /* styleMyShotsButton test: */
 .styleMyShotsButton-bright .myshots-button {
   color: #fff;
-  background: #0996F8; }
+  background: #009ec0; }
 
 .styleMyShotsButton-bright .myshots-text-pre,
 .styleMyShotsButton-bright .myshots-text-post {
   filter: brightness(20); }
 
 /* end styleMyShotsButton test */
 @keyframes pulse {
   0% {
--- a/browser/extensions/screenshots/webextension/build/onboardingCss.js
+++ b/browser/extensions/screenshots/webextension/build/onboardingCss.js
@@ -57,17 +57,17 @@ body {
   animation: fade-in 250ms forwards cubic-bezier(0.07, 0.95, 0, 1);
   opacity: 0; }
 
 .slide {
   display: flex;
   align-items: center;
   flex-direction: column;
   justify-content: center;
-  background-color: #f2f2f2;
+  background-color: #f5f5f7;
   border-radius: 5px;
   height: 520px;
   overflow: hidden;
   width: 700px; }
   .slide .slide-image {
     background-size: 700px 378px;
     flex: 0 0 360px;
     font-size: 16px;
@@ -86,18 +86,17 @@ body {
     font-weight: 400;
     margin: 0 0 10px; }
     .slide h1 sup {
       background: #00d1e6;
       border-radius: 2px;
       color: #fff;
       font-size: 16px;
       margin-left: 5px;
-      padding: 2px;
-      text-transform: uppercase; }
+      padding: 2px; }
   .slide p {
     animation-duration: 350ms;
     font-size: 16px;
     line-height: 23px;
     margin: 0;
     width: 75%; }
   .slide .slide-content-aligner h1 {
     font-size: 34px; }
@@ -141,17 +140,17 @@ body {
 #slide-status-container {
   display: flex;
   align-items: center;
   justify-content: center;
   padding-top: 15px; }
 
 .goto-slide {
   background: transparent;
-  background-color: #f2f2f2;
+  background-color: #f5f5f7;
   border-radius: 50%;
   border: 0;
   flex: 0 0 9px;
   height: 9px;
   margin: 0 4px;
   opacity: 0.7;
   padding: 0;
   transition: height 100ms cubic-bezier(0.07, 0.95, 0, 1), opacity 100ms cubic-bezier(0.07, 0.95, 0, 1); }
@@ -177,68 +176,101 @@ body {
   margin-top: -70px;
   position: absolute;
   text-align: center;
   top: 50%;
   transition: background-color 150ms cubic-bezier(0.07, 0.95, 0, 1), background-size 250ms cubic-bezier(0.07, 0.95, 0, 1);
   width: 70px; }
 
 #prev {
+  background-image: url("MOZ_EXTENSION/icons/back.svg");
   left: 50%;
   margin-left: -385px; }
 
 #next,
 #done {
   left: 50%;
   margin-left: 315px; }
 
 #prev,
 #next,
 #done {
   background-position: center center;
   background-repeat: no-repeat;
   background-size: 20px 20px; }
+  #prev:hover,
+  #next:hover,
+  #done:hover {
+    background-color: #fff;
+    background-size: 22px 22px; }
+  #prev:active,
+  #next:active,
+  #done:active {
+    background-color: #fff;
+    background-size: 24px 24px; }
 
 #next {
+  background-image: url("MOZ_EXTENSION/icons/back.svg");
   transform: rotate(180deg); }
+  .active-slide-1 #next {
+    background-image: url("MOZ_EXTENSION/icons/back-highlight.svg"); }
 
 #skip {
   background: none;
   border: 0;
   color: #fff;
   font-size: 16px;
   left: 50%;
   margin-left: -330px;
   margin-top: 257px;
   opacity: 0.7;
   position: absolute;
   top: 50%;
   transition: opacity 100ms cubic-bezier(0.07, 0.95, 0, 1);
   z-index: 10; }
 
-#prev:hover,
-#next:hover,
-#done:hover {
-  background-color: #fff;
-  background-size: 22px 22px; }
-
-#prev:active,
-#next:active,
-#done:active {
-  background-color: #fff;
-  background-size: 24px 24px; }
-
 #skip:hover {
   opacity: 1; }
 
 .active-slide-1 #prev,
 .active-slide-4 #next {
   display: none; }
 
 #done {
+  background-image: url("MOZ_EXTENSION/icons/done.svg");
   display: none; }
 
 .active-slide-4 #done {
   display: inline-block; }
 
+/* for smaller screen sizes */
+@media screen and (max-width: 768px) {
+  .slide {
+    height: 360px;
+    width: 450px; }
+    .slide .slide-image {
+      background-size: contain;
+      background-repeat: no-repeat;
+      background-position: center;
+      flex: 0 0 200px; }
+    .slide .slide-content {
+      flex: 0 0 160px; }
+      .slide .slide-content h1 {
+        font-size: 24px; }
+      .slide .slide-content p {
+        font-size: 14px;
+        line-height: 21px;
+        width: 85%; }
+      .slide .slide-content .onboarding-legal-notice {
+        font-size: 10px;
+        line-height: 16px; }
+  #skip {
+    margin-left: -205px;
+    margin-top: 177px; }
+  #prev {
+    margin-left: -260px; }
+  #next,
+  #done {
+    margin-left: 190px; } }
+
 `;
 null;
 
--- a/browser/extensions/screenshots/webextension/build/onboardingHtml.js
+++ b/browser/extensions/screenshots/webextension/build/onboardingHtml.js
@@ -41,19 +41,19 @@ window.onboardingHtml = `
           <div class="slide-content">
             <h1 data-l10n-id="tourHeaderFour"></h1>
             <p data-l10n-id="tourBodyFour"></p>
           </div>
         </div>
 
         <!-- Clickable elements should be buttons for accessibility -->
         <button id="skip" data-l10n-id="tourSkip" tabindex=1>Skip</button>
-        <button id="prev" tabindex=2 data-l10n-label-id="tourPrevious" style="background-image: url('MOZ_EXTENSION/icons/back.svg');"></button>
-        <button id="next" tabindex=3 data-l10n-label-id="tourNext" style="background-image: url('MOZ_EXTENSION/icons/back.svg');"/></button>
-        <button id="done" tabindex=4 data-l10n-label-id="tourDone" style="background-image: url('MOZ_EXTENSION/icons/done.svg')"></button>
+        <button id="prev" tabindex=2 data-l10n-label-id="tourPrevious"></button>
+        <button id="next" tabindex=3 data-l10n-label-id="tourNext"></button>
+        <button id="done" tabindex=4 data-l10n-label-id="tourDone"></button>
         <div id="slide-status-container">
           <button class="goto-slide goto-slide-1" data-number="1" tabindex=4></button>
           <button class="goto-slide goto-slide-2" data-number="2" tabindex=5></button>
           <button class="goto-slide goto-slide-3" data-number="3" tabindex=6></button>
           <button class="goto-slide goto-slide-4" data-number="4" tabindex=7></button>
         </div>
         <!-- FIXME: Need to put in privacy / etc links -->
       </div>
--- a/browser/extensions/screenshots/webextension/build/raven.js
+++ b/browser/extensions/screenshots/webextension/build/raven.js
@@ -1,9 +1,9 @@
-/*! Raven.js 3.14.0 (6b817d7) | github.com/getsentry/raven-js */
+/*! Raven.js 3.14.2 (5cf57e1) | github.com/getsentry/raven-js */
 
 /*
  * Includes TraceKit
  * https://github.com/getsentry/TraceKit
  *
  * Copyright 2017 Matt Robenolt and other contributors
  * Released under the BSD license
  * https://github.com/getsentry/raven-js/blob/master/LICENSE
@@ -150,17 +150,17 @@ function Raven() {
  * @this {Raven}
  */
 
 Raven.prototype = {
     // Hardcode version string so that raven source can be loaded directly via
     // webpack (using a build step causes webpack #1617). Grunt verifies that
     // this value matches package.json during build.
     //   See: https://github.com/getsentry/raven-js/issues/465
-    VERSION: '3.14.0',
+    VERSION: '3.14.2',
 
     debug: false,
 
     TraceKit: TraceKit, // alias to TraceKit
 
     /*
      * Configure Raven with a DSN and extra options
      *
@@ -1409,29 +1409,31 @@ Raven.prototype = {
     },
 
     /**
      * Truncate breadcrumb values (right now just URLs)
      */
     _trimBreadcrumbs: function (breadcrumbs) {
         // known breadcrumb properties with urls
         // TODO: also consider arbitrary prop values that start with (https?)?://
-        var urlprops = {to: 1, from: 1, url: 1},
+        var urlProps = ['to', 'from', 'url'],
+            urlProp,
             crumb,
             data;
 
-        for (var i = 0; i < breadcrumbs.values.length; i++) {
+        for (var i = 0; i < breadcrumbs.values.length; ++i) {
             crumb = breadcrumbs.values[i];
-            if (!crumb.hasOwnProperty('data'))
+            if (!crumb.hasOwnProperty('data') || !isObject(crumb.data))
                 continue;
 
             data = crumb.data;
-            for (var prop in urlprops) {
-                if (data.hasOwnProperty(prop)) {
-                    data[prop] = truncate(data[prop], this._globalOptions.maxUrlLength);
+            for (var j = 0; j < urlProps.length; ++j) {
+                urlProp = urlProps[j];
+                if (data.hasOwnProperty(urlProp)) {
+                    data[urlProp] = truncate(data[urlProp], this._globalOptions.maxUrlLength);
                 }
             }
         }
     },
 
     _getHttpData: function() {
         if (!this._hasNavigator && !this._hasDocument) return;
         var httpData = {};
@@ -2122,30 +2124,32 @@ module.exports = Raven;
 }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
 },{"3":3}],5:[function(_dereq_,module,exports){
 'use strict';
 
 function isObject(what) {
     return typeof what === 'object' && what !== null;
 }
 
-// Sorta yanked from https://github.com/joyent/node/blob/aa3b4b4/lib/util.js#L560
+// Yanked from https://git.io/vS8DV re-used under CC0
 // with some tiny modifications
-function isError(what) {
-    var toString = {}.toString.call(what);
-    return isObject(what) &&
-        toString === '[object Error]' ||
-        toString === '[object Exception]' || // Firefox NS_ERROR_FAILURE Exceptions
-        what instanceof Error;
+function isError(value) {
+  switch ({}.toString.call(value)) {
+    case '[object Error]': return true;
+    case '[object Exception]': return true;
+    case '[object DOMException]': return true;
+    default: return value instanceof Error;
+  }
 }
 
 module.exports = {
     isObject: isObject,
     isError: isError
 };
+
 },{}],6:[function(_dereq_,module,exports){
 (function (global){
 'use strict';
 
 var utils = _dereq_(5);
 
 /*
  TraceKit - Cross brower stack traces
@@ -2463,37 +2467,16 @@ TraceKit.report = (function reportModule
  * This is okay for tracing (because you are likely to be calling
  * computeStackTrace from the function you want to be the topmost element
  * of the stack trace anyway), but not okay for logging unhandled
  * exceptions (because your catch block will likely be far away from the
  * inner function that actually caused the exception).
  *
  */
 TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
-    /**
-     * Escapes special characters, except for whitespace, in a string to be
-     * used inside a regular expression as a string literal.
-     * @param {string} text The string.
-     * @return {string} The escaped string literal.
-     */
-    function escapeRegExp(text) {
-        return text.replace(/[\-\[\]{}()*+?.,\\\^$|#]/g, '\\$&');
-    }
-
-    /**
-     * Escapes special characters in a string to be used inside a regular
-     * expression as a string literal. Also ensures that HTML entities will
-     * be matched the same as their literal friends.
-     * @param {string} body The string.
-     * @return {string} The escaped string.
-     */
-    function escapeCodeAsRegExpForMatchingInsideHTML(body) {
-        return escapeRegExp(body).replace('<', '(?:<|&lt;)').replace('>', '(?:>|&gt;)').replace('&', '(?:&|&amp;)').replace('"', '(?:"|&quot;)').replace(/\s+/g, '\\s+');
-    }
-
     // Contents of Exception in various browsers.
     //
     // SAFARI:
     // ex.message = Can't find variable: qq
     // ex.line = 59
     // ex.sourceId = 580238192
     // ex.sourceURL = http://...
     // ex.expressionBeginOffset = 96
--- a/browser/extensions/screenshots/webextension/build/shot.js
+++ b/browser/extensions/screenshots/webextension/build/shot.js
@@ -29,38 +29,38 @@ function isUrl(url) {
   }
   if ((/^view-source:/i).test(url)) {
     return isUrl(url.substr("view-source:".length));
   }
   return (/^https?:\/\/[a-z0-9\.\-]+[a-z0-9](:[0-9]+)?\/?/i).test(url);
 }
 
 function assertUrl(url) {
-  if (! url) {
+  if (!url) {
     throw new Error("Empty value is not URL");
   }
-  if (! isUrl(url)) {
+  if (!isUrl(url)) {
     let exc = new Error("Not a URL");
     exc.scheme = url.split(":")[0];
     throw exc;
   }
 }
 
 function assertOrigin(url) {
   assertUrl(url);
   if (url.search(/^https?:/i) != -1) {
     let match = (/^https?:\/\/[^/:]+\/?$/i).exec(url);
-    if (! match) {
+    if (!match) {
       throw new Error("Bad origin, might include path");
     }
   }
 }
 
 function originFromUrl(url) {
-  if (! url) {
+  if (!url) {
     return null;
   }
   if (url.search(/^https?:/i) == -1) {
     // Non-HTTP URLs don't have an origin
     return null;
   }
   let match = (/^https?:\/\/[^/:]+/i).exec(url);
   if (match) {
@@ -72,17 +72,17 @@ function originFromUrl(url) {
 /** Check if the given object has all of the required attributes, and no extra
     attributes exception those in optional */
 function checkObject(obj, required, optional) {
   if (typeof obj != "object" || obj === null) {
     throw new Error("Cannot check non-object: " + (typeof obj) + " that is " + JSON.stringify(obj));
   }
   required = required || [];
   for (let attr of required) {
-    if (! (attr in obj)) {
+    if (!(attr in obj)) {
       return false;
     }
   }
   optional = optional || [];
   for (let attr in obj) {
     if (required.indexOf(attr) == -1 && optional.indexOf(attr) == -1) {
       return false;
     }
@@ -141,54 +141,54 @@ function resolveUrl(base, url) {
 function deepEqual(a, b) {
   if ((a === null || a === undefined) && (b === null || b === undefined)) {
     return true;
   }
   if (typeof a != "object" || typeof b != "object") {
     return a === b;
   }
   if (Array.isArray(a)) {
-    if (! Array.isArray(b)) {
+    if (!Array.isArray(b)) {
       return false;
     }
     if (a.length != b.length) {
       return false;
     }
-    for (let i=0; i<a.length; i++) {
-      if (! deepEqual(a[i], b[i])) {
+    for (let i = 0; i < a.length; i++) {
+      if (!deepEqual(a[i], b[i])) {
         return false;
       }
     }
   }
   if (Array.isArray(b)) {
     return false;
   }
   let seen = new Set();
   for (let attr of Object.keys(a)) {
-    if (! deepEqual(a[attr], b[attr])) {
+    if (!deepEqual(a[attr], b[attr])) {
       return false;
     }
     seen.add(attr);
   }
   for (let attr of Object.keys(b)) {
-    if (! seen.has(attr)) {
-      if (! deepEqual(a[attr], b[attr])) {
+    if (!seen.has(attr)) {
+      if (!deepEqual(a[attr], b[attr])) {
         return false;
       }
     }
   }
   return true;
 }
 
 function makeRandomId() {
   // Note: this isn't for secure contexts, only for non-conflicting IDs
   let id = "";
   while (id.length < 12) {
     let num;
-    if (! id) {
+    if (!id) {
       num = Date.now() % Math.pow(36, 3);
     } else {
       num = Math.floor(Math.random() * Math.pow(36, 3));
     }
     id += num.toString(36);
   }
   return id;
 }
@@ -197,17 +197,17 @@ class AbstractShot {
 
   constructor(backend, id, attrs) {
     attrs = attrs || {};
     assert((/^[a-zA-Z0-9]+\/[a-z0-9\.-]+$/).test(id), "Bad ID (should be alphanumeric):", JSON.stringify(id));
     this._backend = backend;
     this._id = id;
     this.origin = attrs.origin || null;
     this.fullUrl = attrs.fullUrl || null;
-    if ((! attrs.fullUrl) && attrs.url) {
+    if ((!attrs.fullUrl) && attrs.url) {
       console.warn("Received deprecated attribute .url");
       this.fullUrl = attrs.url;
     }
     this.docTitle = attrs.docTitle || null;
     this.userTitle = attrs.userTitle || null;
     this.createdDate = attrs.createdDate || Date.now();
     this.favicon = attrs.favicon || null;
     this.siteName = attrs.siteName || null;
@@ -249,31 +249,31 @@ class AbstractShot {
       if (attr == "clips") {
         continue;
       }
       if (typeof json[attr] == "object" && typeof this[attr] == "object" && this[attr] !== null) {
         let val = this[attr];
         if (val.asJson) {
           val = val.asJson();
         }
-        if (! deepEqual(json[attr], val)) {
+        if (!deepEqual(json[attr], val)) {
           this[attr] = json[attr];
         }
       } else if (json[attr] !== this[attr] &&
           (json[attr] || this[attr])) {
         this[attr] = json[attr];
       }
     }
     if (json.clips) {
       for (let clipId in json.clips) {
-        if (! json.clips[clipId]) {
+        if (!json.clips[clipId]) {
           this.delClip(clipId);
-        } else if (! this.getClip(clipId)) {
+        } else if (!this.getClip(clipId)) {
           this.setClip(clipId, json.clips[clipId]);
-        } else if (! deepEqual(this.getClip(clipId).asJson(), json.clips[clipId])) {
+        } else if (!deepEqual(this.getClip(clipId).asJson(), json.clips[clipId])) {
           this.setClip(clipId, json.clips[clipId]);
         }
       }
     }
 
   }
 
   /** Returns a JSON version of this shot */
@@ -355,32 +355,31 @@ class AbstractShot {
       const excedingchars = (clipFilenameBytesSize - 246) / 2; // 251 - 5 for ellipsis "[...]"
       clipFilename = clipFilename.substring(0, clipFilename.length - excedingchars);
       clipFilename = clipFilename + '[...]';
     }
     return clipFilename + '.png';
   }
 
   get urlDisplay() {
-    if (! this.url) {
+    if (!this.url) {
       return null;
     }
     if (this.url.search(/^https?/i) != -1) {
       let txt = this.url;
       txt = txt.replace(/^[a-z]+:\/\//i, "");
       txt = txt.replace(/\/.*/, "");
       txt = txt.replace(/^www\./i, "");
       return txt;
     } else if (this.url.startsWith("data:")) {
       return "data:url";
-    } else {
-      let txt = this.url;
-      txt = txt.replace(/\?.*/, "");
-      return txt;
     }
+    let txt = this.url;
+    txt = txt.replace(/\?.*/, "");
+    return txt;
   }
 
   get viewUrl() {
     let url = this.backend + "/" + this.id;
     return url;
   }
 
   get creatingUrl() {
@@ -467,17 +466,17 @@ class AbstractShot {
     if (val) {
       val = resolveUrl(this.url, val);
     }
     this._favicon = val;
   }
 
   clipNames() {
     let names = Object.getOwnPropertyNames(this._clips);
-    names.sort(function (a, b) {
+    names.sort(function(a, b) {
       return a.sortOrder < b.sortOrder ? 1 : 0;
     });
     return names;
   }
   getClip(name) {
     return this._clips[name];
   }
   addClip(val) {
@@ -485,17 +484,17 @@ class AbstractShot {
     this.setClip(name, val);
     return name;
   }
   setClip(name, val) {
     let clip = new this.Clip(this, name, val);
     this._clips[name] = clip;
   }
   delClip(name) {
-    if (! this._clips[name]) {
+    if (!this._clips[name]) {
       throw new Error("No existing clip with id: " + name);
     }
     delete this._clips[name];
   }
   biggestClipSortOrder() {
     let biggest = 0;
     for (let clipId in this._clips) {
       biggest = Math.max(biggest, this._clips[clipId].sortOrder);
@@ -510,40 +509,40 @@ class AbstractShot {
       console.warn("Tried to update the url of a clip with no image:", clip);
     }
   }
 
   get siteName() {
     return this._siteName || null;
   }
   set siteName(val) {
-    assert(typeof val == "string" || ! val);
+    assert(typeof val == "string" || !val);
     this._siteName = val;
   }
 
   get documentSize() {
     return this._documentSize;
   }
   set documentSize(val) {
-    assert(typeof val == "object" || ! val);
+    assert(typeof val == "object" || !val);
     if (val) {
       assert(checkObject(val, ["height", "width"], "Bad attr to documentSize:", Object.keys(val)));
       assert(typeof val.height == "number");
       assert(typeof val.width == "number");
       this._documentSize = val;
     } else {
       this._documentSize = null;
     }
   }
 
   get fullScreenThumbnail() {
     return this._fullScreenThumbnail;
   }
   set fullScreenThumbnail(val) {
-    assert(typeof val == "string" || ! val);
+    assert(typeof val == "string" || !val);
     if (val) {
       assert(isUrl(val));
       this._fullScreenThumbnail = val;
     } else {
       this._fullScreenThumbnail = null;
     }
   }
 
@@ -551,17 +550,17 @@ class AbstractShot {
     return this._abTests;
   }
   set abTests(val) {
     if (val === null || val === undefined) {
       this._abTests = null;
       return;
     }
     assert(typeof val == "object", "abTests should be an object, not:", typeof val);
-    assert(! Array.isArray(val), "abTests should not be an Array");
+    assert(!Array.isArray(val), "abTests should not be an Array");
     for (let name in val) {
       assert(val[name] && typeof val[name] == "string", `abTests.${name} should be a string:`, typeof val[name]);
     }
     this._abTests = val;
   }
 
 }
 
@@ -601,23 +600,23 @@ player player:width player:height player
 class _Image {
   // FIXME: either we have to notify the shot of updates, or make
   // this read-only
   constructor(json) {
     assert(typeof json === "object", "Clip Image given a non-object", json);
     assert(checkObject(json, ["url"], ["dimensions", "title", "alt"]), "Bad attrs for Image:", Object.keys(json));
     assert(isUrl(json.url), "Bad Image url:", json.url);
     this.url = json.url;
-    assert((! json.dimensions) ||
+    assert((!json.dimensions) ||
            (typeof json.dimensions.x == "number" && typeof json.dimensions.y == "number"),
            "Bad Image dimensions:", json.dimensions);
     this.dimensions = json.dimensions;
-    assert(typeof json.title == "string" || ! json.title, "Bad Image title:", json.title);
+    assert(typeof json.title == "string" || !json.title, "Bad Image title:", json.title);
     this.title = json.title;
-    assert(typeof json.alt == "string" || ! json.alt, "Bad Image alt:", json.alt);
+    assert(typeof json.alt == "string" || !json.alt, "Bad Image alt:", json.alt);
     this.alt = json.alt;
   }
 
   asJson() {
     return jsonify(this, ["url"], ["dimensions"]);
   }
 }
 
@@ -627,17 +626,17 @@ AbstractShot.prototype.Image = _Image;
 class _Clip {
   constructor(shot, id, json) {
     this._shot = shot;
     assert(checkObject(json, ["createdDate", "image"], ["sortOrder"]), "Bad attrs for Clip:", Object.keys(json));
     assert(typeof id == "string" && id, "Bad Clip id:", id);
     this._id = id;
     this.createdDate = json.createdDate;
     if ('sortOrder' in json) {
-      assert(typeof json.sortOrder == "number" || ! json.sortOrder, "Bad Clip sortOrder:", json.sortOrder);
+      assert(typeof json.sortOrder == "number" || !json.sortOrder, "Bad Clip sortOrder:", json.sortOrder);
     }
     if ('sortOrder' in json) {
       this.sortOrder = json.sortOrder;
     } else {
       let biggestOrder = shot.biggestClipSortOrder();
       this.sortOrder = biggestOrder + 100;
     }
     this.image = json.image;
@@ -654,32 +653,32 @@ class _Clip {
   get id() {
     return this._id;
   }
 
   get createdDate() {
     return this._createdDate;
   }
   set createdDate(val) {
-    assert(typeof val == "number" || ! val, "Bad Clip createdDate:", val);
+    assert(typeof val == "number" || !val, "Bad Clip createdDate:", val);
     this._createdDate = val;
   }
 
   get image() {
     return this._image;
   }
   set image(image) {
-    if (! image) {
+    if (!image) {
       this._image = undefined;
       return;
     }
     assert(checkObject(image, ["url"], ["dimensions", "text", "location", "captureType"]), "Bad attrs for Clip Image:", Object.keys(image));
     assert(isUrl(image.url), "Bad Clip image URL:", image.url);
-    assert(image.captureType == "madeSelection" || image.captureType == "selection" || image.captureType == "visible" || image.captureType == "auto" || image.captureType == "fullPage" || ! image.captureType, "Bad image.captureType:", image.captureType);
-    assert(typeof image.text == "string" || ! image.text, "Bad Clip image text:", image.text);
+    assert(image.captureType == "madeSelection" || image.captureType == "selection" || image.captureType == "visible" || image.captureType == "auto" || image.captureType == "fullPage" || !image.captureType, "Bad image.captureType:", image.captureType);
+    assert(typeof image.text == "string" || !image.text, "Bad Clip image text:", image.text);
     if (image.dimensions) {
       assert(typeof image.dimensions.x == "number" && typeof image.dimensions.y == "number", "Bad Clip image dimensions:", image.dimensions);
     }
     assert(image.location &&
       typeof image.location.left == "number" &&
       typeof image.location.right == "number" &&
       typeof image.location.top == "number" &&
       typeof image.location.bottom == "number", "Bad Clip image pixel location:", image.location);
@@ -697,23 +696,24 @@ class _Clip {
     }
     this._image = image;
   }
 
   isDataUrl() {
     if (this.image) {
       return this.image.url.startsWith("data:");
     }
+    return false;
   }
 
   get sortOrder() {
     return this._sortOrder || null;
   }
   set sortOrder(val) {
-    assert(typeof val == "number" || ! val, "Bad Clip sortOrder:", val);
+    assert(typeof val == "number" || !val, "Bad Clip sortOrder:", val);
     this._sortOrder = val;
   }
 
 }
 
 AbstractShot.prototype.Clip = _Clip;
 
 if (typeof exports != "undefined") {
--- a/browser/extensions/screenshots/webextension/catcher.js
+++ b/browser/extensions/screenshots/webextension/catcher.js
@@ -1,25 +1,25 @@
-/* globals log */
-
 "use strict";
 
 var global = this;
 
-this.catcher = (function () {
+this.catcher = (function() {
   let exports = {};
 
   let handler;
 
   let queue = [];
 
-  exports.unhandled = function (error, info) {
+  let log = global.log;
+
+  exports.unhandled = function(error, info) {
     log.error("Unhandled error:", error, info);
     let e = makeError(error, info);
-    if (! handler) {
+    if (!handler) {
       queue.push(e);
     } else {
       handler(e);
     }
   };
 
   /** Turn an exception into an error object */
   function makeError(exc, info) {
@@ -42,36 +42,41 @@ this.catcher = (function () {
         result[attr] = info[attr];
       }
     }
     return result;
   }
 
   /** Wrap the function, and if it raises any exceptions then call unhandled() */
   exports.watchFunction = function watchFunction(func) {
-    return function () {
+    return function() {
       try {
         return func.apply(this, arguments);
       } catch (e) {
         exports.unhandled(e);
         throw e;
       }
     };
   };
 
-  exports.watchPromise = function watchPromise(promise) {
+  exports.watchPromise = function watchPromise(promise, quiet) {
     return promise.catch((e) => {
-      log.error("------Error in promise:", e);
-      log.error(e.stack);
-      exports.unhandled(makeError(e));
+      if (quiet) {
+        log.debug("------Error in promise:", e);
+        log.debug(e.stack);
+      } else {
+        log.error("------Error in promise:", e);
+        log.error(e.stack);
+        exports.unhandled(makeError(e));
+      }
       throw e;
     });
   };
 
-  exports.registerHandler = function (h) {
+  exports.registerHandler = function(h) {
     if (handler) {
       log.error("registerHandler called after handler was already registered");
       return;
     }
     handler = h;
     for (let error of queue) {
       handler(error);
     }
--- a/browser/extensions/screenshots/webextension/clipboard.js
+++ b/browser/extensions/screenshots/webextension/clipboard.js
@@ -1,16 +1,16 @@
 /* globals catcher */
 
 "use strict";
 
-this.clipboard = (function () {
+this.clipboard = (function() {
   let exports = {};
 
-  exports.copy = function (text) {
+  exports.copy = function(text) {
     let el = document.createElement("textarea");
     document.body.appendChild(el);
     el.value = text;
     el.select();
     const copied = document.execCommand("copy");
     document.body.removeChild(el);
     if (!copied) {
       catcher.unhandled(new Error("Clipboard copy failed"));
--- a/browser/extensions/screenshots/webextension/domainFromUrl.js
+++ b/browser/extensions/screenshots/webextension/domainFromUrl.js
@@ -1,29 +1,29 @@
 /** Returns the domain of a URL, but safely and in ASCII; URLs without domains
     (such as about:blank) return the scheme, Unicode domains get stripped down
     to ASCII */
 
 "use strict";
 
-this.domainFromUrl = (function () {
+this.domainFromUrl = (function() {
 
   return function urlDomainForId(location) { // eslint-disable-line no-unused-vars
     let domain = location.hostname;
     if (!domain) {
       domain = location.origin.split(":")[0];
-      if (! domain) {
+      if (!domain) {
         domain = "unknown";
       }
     }
     if (domain.search(/^[a-z0-9.\-]+$/i) === -1) {
       // Probably a unicode domain; we could use punycode but it wouldn't decode
       // well in the URL anyway.  Instead we'll punt.
       domain = domain.replace(/[^a-z0-9.\-]/ig, "");
-      if (! domain) {
+      if (!domain) {
         domain = "site";
       }
     }
     return domain;
   };
 
 })();
 null;
new file mode 100644
--- /dev/null
+++ b/browser/extensions/screenshots/webextension/icons/back-highlight.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 20 20" style="enable-background:new 0 0 20 20;" xml:space="preserve">
+<style type="text/css">
+	.st0{fill:#009EC0;}
+</style>
+<path id="path-1_1_" class="st0" fill="#3D3D40" d="M18.8,8.5H4.2l5.4-5.4c0.5-0.5,0.5-1.2,0-1.8s-1.2-0.5-1.8,0L0.4,8.9c-0.5,0.5-0.5,1.2,0,1.8
+	l7.5,7.5c0.2,0.2,0.5,0.4,0.9,0.4s0.6-0.1,0.9-0.4c0.5-0.5,0.5-1.2,0-1.8L4.2,11h14.5c0.8,0,1.2-0.5,1.2-1.2S19.5,8.5,18.8,8.5z"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/browser/extensions/screenshots/webextension/icons/icon-16.svg
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 43.2 (39069) - http://www.bohemiancoding.com/sketch -->
+    <title>icon-16</title>
+    <desc>Created with Sketch.</desc>
+    <defs></defs>
+    <g id="Onboarding" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="icon" fill="#4D4D4D">
+            <path d="M11,2 L15,2 L15,4 L11,4 L11,2 Z M17,2 L21,2 L21,4 L17,4 L17,2 Z M14,28 L18,28 L21,28 L21,30 L14,30 L14,28 Z M28,11 L30,11 L30,15 L28,15 L28,11 Z M28,17 L30,17 L30,21 L28,21 L28,17 Z M30,3.00292933 L30,9 L28,9 L28,4.49769878 C28,4.21484375 27.7771727,4 27.5023012,4 L23,4 L23,2 L28.9970707,2 C29.5621186,2 30,2.44902676 30,3.00292933 Z M28.9970707,30 L23,30 L23,28 L27.5023012,28 C27.7851562,28 28,27.7771727 28,27.5023012 L28,23 L30,23 L30,28.9970707 C30,29.5621186 29.5509732,30 28.9970707,30 Z M9,2 L9,4 L4.49769878,4 C4.21484375,4 4,4.22595492 4,4.50468445 L4,6 L2,6 L2,3.0093689 C2,2.44335318 2.44902676,2 3.00292933,2 L9,2 Z" id="Combined-Shape"></path>
+            <path d="M7.5,18 C4.46243388,18 2,15.5375661 2,12.5 C2,9.46243388 4.46243388,7 7.5,7 C10.5375661,7 13,9.46243388 13,12.5 C13,15.5375661 10.5375661,18 7.5,18 Z M7.5,15.25 C9.01878306,15.25 10.25,14.0187831 10.25,12.5 C10.25,10.9812169 9.01878306,9.75 7.5,9.75 C5.98121694,9.75 4.75,10.9812169 4.75,12.5 C4.75,14.0187831 5.98121694,15.25 7.5,15.25 Z" id="Combined-Shape"></path>
+            <path d="M7.5,30 C4.46243388,30 2,27.5375661 2,24.5 C2,21.4624339 4.46243388,19 7.5,19 C10.5375661,19 13,21.4624339 13,24.5 C13,27.5375661 10.5375661,30 7.5,30 Z M7.5,27.25 C9.01878306,27.25 10.25,26.0187831 10.25,24.5 C10.25,22.9812169 9.01878306,21.75 7.5,21.75 C5.98121694,21.75 4.75,22.9812169 4.75,24.5 C4.75,26.0187831 5.98121694,27.25 7.5,27.25 Z" id="Combined-Shape-Copy"></path>
+            <path d="M17.5,17.1107468 C15.3660747,15.6044466 13.2177087,14.087953 11.6169865,12.9580314 C10.6291131,12.260709 8.43228761,15.6061621 9.47511461,16.3422753 L14.0318913,19.5588235 L17.5,17.1107468 Z M20.9681087,19.5588235 C23.6164424,21.4282356 25.6533664,22.8660643 25.6533664,22.8660643 C26.5557642,23.5030509 26.7709224,24.7509686 26.1339357,25.6533664 C25.4969491,26.5557642 24.2490314,26.7709224 23.3466336,26.1339357 L17.5,22.0069002 C18.6001,21.2303591 19.7896836,20.390653 20.9681087,19.5588235 Z" id="Combined-Shape" fill-rule="nonzero"></path>
+            <path d="M12.0225886,23.7556612 L25.6533664,14.1339357 C26.5557642,13.4969491 26.7709224,12.2490314 26.1339357,11.3466336 C25.4969491,10.4442358 24.2490314,10.2290776 23.3466336,10.8660643 L9.80606657,20.4241116 C8.65292225,21.2380958 10.8995145,24.5484194 12.0225886,23.7556612 Z" id="Line" fill-rule="nonzero"></path>
+        </g>
+    </g>
+</svg>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/extensions/screenshots/webextension/icons/icon-32.svg
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 43.2 (39069) - http://www.bohemiancoding.com/sketch -->
+    <title>icon-32</title>
+    <desc>Created with Sketch.</desc>
+    <defs></defs>
+    <g id="Onboarding" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="icon" fill="#4D4D4D">
+            <path d="M11,2 L15,2 L15,4 L11,4 L11,2 Z M17,2 L21,2 L21,4 L17,4 L17,2 Z M14,28 L18,28 L21,28 L21,30 L14,30 L14,28 Z M28,11 L30,11 L30,15 L28,15 L28,11 Z M28,17 L30,17 L30,21 L28,21 L28,17 Z M30,3.00292933 L30,9 L28,9 L28,4.49769878 C28,4.21484375 27.7771727,4 27.5023012,4 L23,4 L23,2 L28.9970707,2 C29.5621186,2 30,2.44902676 30,3.00292933 Z M28.9970707,30 L23,30 L23,28 L27.5023012,28 C27.7851562,28 28,27.7771727 28,27.5023012 L28,23 L30,23 L30,28.9970707 C30,29.5621186 29.5509732,30 28.9970707,30 Z M9,2 L9,4 L4.49769878,4 C4.21484375,4 4,4.22595492 4,4.50468445 L4,6 L2,6 L2,3.0093689 C2,2.44335318 2.44902676,2 3.00292933,2 L9,2 Z" id="Combined-Shape"></path>
+            <path d="M7.5,18 C4.46243388,18 2,15.5375661 2,12.5 C2,9.46243388 4.46243388,7 7.5,7 C10.5375661,7 13,9.46243388 13,12.5 C13,15.5375661 10.5375661,18 7.5,18 Z M7.5,15.25 C9.01878306,15.25 10.25,14.0187831 10.25,12.5 C10.25,10.9812169 9.01878306,9.75 7.5,9.75 C5.98121694,9.75 4.75,10.9812169 4.75,12.5 C4.75,14.0187831 5.98121694,15.25 7.5,15.25 Z" id="Combined-Shape"></path>
+            <path d="M7.5,30 C4.46243388,30 2,27.5375661 2,24.5 C2,21.4624339 4.46243388,19 7.5,19 C10.5375661,19 13,21.4624339 13,24.5 C13,27.5375661 10.5375661,30 7.5,30 Z M7.5,27.25 C9.01878306,27.25 10.25,26.0187831 10.25,24.5 C10.25,22.9812169 9.01878306,21.75 7.5,21.75 C5.98121694,21.75 4.75,22.9812169 4.75,24.5 C4.75,26.0187831 5.98121694,27.25 7.5,27.25 Z" id="Combined-Shape-Copy"></path>
+            <path d="M17.5,17.1107468 C15.3660747,15.6044466 13.2177087,14.087953 11.6169865,12.9580314 C10.6291131,12.260709 8.43228761,15.6061621 9.47511461,16.3422753 L14.0318913,19.5588235 L17.5,17.1107468 Z M20.9681087,19.5588235 C23.6164424,21.4282356 25.6533664,22.8660643 25.6533664,22.8660643 C26.5557642,23.5030509 26.7709224,24.7509686 26.1339357,25.6533664 C25.4969491,26.5557642 24.2490314,26.7709224 23.3466336,26.1339357 L17.5,22.0069002 C18.6001,21.2303591 19.7896836,20.390653 20.9681087,19.5588235 Z" id="Combined-Shape" fill-rule="nonzero"></path>
+            <path d="M12.0225886,23.7556612 L25.6533664,14.1339357 C26.5557642,13.4969491 26.7709224,12.2490314 26.1339357,11.3466336 C25.4969491,10.4442358 24.2490314,10.2290776 23.3466336,10.8660643 L9.80606657,20.4241116 C8.65292225,21.2380958 10.8995145,24.5484194 12.0225886,23.7556612 Z" id="Line" fill-rule="nonzero"></path>
+        </g>
+    </g>
+</svg>
\ No newline at end of file
deleted file mode 100644
index 6f84b582bce39b345cbde70c073eef92ca47e50a..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
--- /dev/null
+++ b/browser/extensions/screenshots/webextension/icons/icon-highlight-32.svg
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 43.2 (39069) - http://www.bohemiancoding.com/sketch -->
+    <title>icon-32</title>
+    <desc>Created with Sketch.</desc>
+    <defs></defs>
+    <g id="Onboarding" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="icon" fill="#989898">
+            <path d="M11,2 L15,2 L15,4 L11,4 L11,2 Z M17,2 L21,2 L21,4 L17,4 L17,2 Z M14,28 L18,28 L21,28 L21,30 L14,30 L14,28 Z M28,11 L30,11 L30,15 L28,15 L28,11 Z M28,17 L30,17 L30,21 L28,21 L28,17 Z M30,3.00292933 L30,9 L28,9 L28,4.49769878 C28,4.21484375 27.7771727,4 27.5023012,4 L23,4 L23,2 L28.9970707,2 C29.5621186,2 30,2.44902676 30,3.00292933 Z M28.9970707,30 L23,30 L23,28 L27.5023012,28 C27.7851562,28 28,27.7771727 28,27.5023012 L28,23 L30,23 L30,28.9970707 C30,29.5621186 29.5509732,30 28.9970707,30 Z M9,2 L9,4 L4.49769878,4 C4.21484375,4 4,4.22595492 4,4.50468445 L4,6 L2,6 L2,3.0093689 C2,2.44335318 2.44902676,2 3.00292933,2 L9,2 Z" id="Combined-Shape"></path>
+            <path d="M7.5,18 C4.46243388,18 2,15.5375661 2,12.5 C2,9.46243388 4.46243388,7 7.5,7 C10.5375661,7 13,9.46243388 13,12.5 C13,15.5375661 10.5375661,18 7.5,18 Z M7.5,15.25 C9.01878306,15.25 10.25,14.0187831 10.25,12.5 C10.25,10.9812169 9.01878306,9.75 7.5,9.75 C5.98121694,9.75 4.75,10.9812169 4.75,12.5 C4.75,14.0187831 5.98121694,15.25 7.5,15.25 Z" id="Combined-Shape"></path>
+            <path d="M7.5,30 C4.46243388,30 2,27.5375661 2,24.5 C2,21.4624339 4.46243388,19 7.5,19 C10.5375661,19 13,21.4624339 13,24.5 C13,27.5375661 10.5375661,30 7.5,30 Z M7.5,27.25 C9.01878306,27.25 10.25,26.0187831 10.25,24.5 C10.25,22.9812169 9.01878306,21.75 7.5,21.75 C5.98121694,21.75 4.75,22.9812169 4.75,24.5 C4.75,26.0187831 5.98121694,27.25 7.5,27.25 Z" id="Combined-Shape-Copy"></path>
+            <path d="M17.5,17.1107468 C15.3660747,15.6044466 13.2177087,14.087953 11.6169865,12.9580314 C10.6291131,12.260709 8.43228761,15.6061621 9.47511461,16.3422753 L14.0318913,19.5588235 L17.5,17.1107468 Z M20.9681087,19.5588235 C23.6164424,21.4282356 25.6533664,22.8660643 25.6533664,22.8660643 C26.5557642,23.5030509 26.7709224,24.7509686 26.1339357,25.6533664 C25.4969491,26.5557642 24.2490314,26.7709224 23.3466336,26.1339357 L17.5,22.0069002 C18.6001,21.2303591 19.7896836,20.390653 20.9681087,19.5588235 Z" id="Combined-Shape" fill-rule="nonzero"></path>
+            <path d="M12.0225886,23.7556612 L25.6533664,14.1339357 C26.5557642,13.4969491 26.7709224,12.2490314 26.1339357,11.3466336 C25.4969491,10.4442358 24.2490314,10.2290776 23.3466336,10.8660643 L9.80606657,20.4241116 C8.65292225,21.2380958 10.8995145,24.5484194 12.0225886,23.7556612 Z" id="Line" fill-rule="nonzero"></path>
+        </g>
+    </g>
+</svg>
deleted file mode 100644
index d1b63f79fba34471259e6bf091011fd10d6edb3e..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
deleted file mode 100644
index 395afb5abfaafa67a51c9ada8acde311f4d239e1..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
--- /dev/null
+++ b/browser/extensions/screenshots/webextension/icons/icon-starred-32.svg
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 43.2 (39069) - http://www.bohemiancoding.com/sketch -->
+    <title>icon-starred-32</title>
+    <desc>Created with Sketch.</desc>
+    <defs></defs>
+    <g id="Onboarding" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="icon-starred">
+            <path d="M11,2 L15,2 L15,4 L11,4 L11,2 Z M17,2 L19,2 L19,4 L17,4 L17,2 Z M14,28 L18,28 L21,28 L21,30 L14,30 L14,28 Z M28,18 L30,18 L30,21 L28,21 L28,18 Z M28.9970707,30 L23,30 L23,28 L27.5023012,28 C27.7851562,28 28,27.7771727 28,27.5023012 L28,23 L30,23 L30,28.9970707 C30,29.5621186 29.5509732,30 28.9970707,30 Z M9,2 L9,4 L4.49769878,4 C4.21484375,4 4,4.22595492 4,4.50468445 L4,6 L2,6 L2,3.0093689 C2,2.44335318 2.44902676,2 3.00292933,2 L9,2 Z" id="Combined-Shape" fill="#4D4D4D"></path>
+            <path d="M7.5,18 C4.46243388,18 2,15.5375661 2,12.5 C2,9.46243388 4.46243388,7 7.5,7 C10.5375661,7 13,9.46243388 13,12.5 C13,15.5375661 10.5375661,18 7.5,18 Z M7.5,15.25 C9.01878306,15.25 10.25,14.0187831 10.25,12.5 C10.25,10.9812169 9.01878306,9.75 7.5,9.75 C5.98121694,9.75 4.75,10.9812169 4.75,12.5 C4.75,14.0187831 5.98121694,15.25 7.5,15.25 Z" id="Combined-Shape" fill="#4D4D4D"></path>
+            <path d="M7.5,30 C4.46243388,30 2,27.5375661 2,24.5 C2,21.4624339 4.46243388,19 7.5,19 C10.5375661,19 13,21.4624339 13,24.5 C13,27.5375661 10.5375661,30 7.5,30 Z M7.5,27.25 C9.01878306,27.25 10.25,26.0187831 10.25,24.5 C10.25,22.9812169 9.01878306,21.75 7.5,21.75 C5.98121694,21.75 4.75,22.9812169 4.75,24.5 C4.75,26.0187831 5.98121694,27.25 7.5,27.25 Z" id="Combined-Shape-Copy" fill="#4D4D4D"></path>
+            <path d="M19.5621306,18.4336316 L12.0225886,23.7556612 C10.8995145,24.5484194 8.65292225,21.2380958 9.80606657,20.4241116 L12.5318913,18.5 L9.47511461,16.3422753 C8.43228761,15.6061621 10.6291131,12.260709 11.6169865,12.9580314 L16,16.0519233 L16.2999464,15.8401964 C16.308319,16.6949285 16.7256347,17.5052335 17.4378266,18.0070314 C18.0631741,18.4476404 18.8359546,18.5940831 19.5621306,18.4336316 Z M20.9681087,19.5588235 L25.6533664,22.8660643 C26.5557642,23.5030509 26.7709224,24.7509686 26.1339357,25.6533664 C25.4969491,26.5557642 24.2490314,26.7709224 23.3466336,26.1339357 L17.5,22.0069002 C18.6001,21.2303591 19.7896836,20.390653 20.9681087,19.5588235 Z" id="Combined-Shape" fill="#4D4D4D" fill-rule="nonzero"></path>
+            <path d="M31.0298163,5.60065296 L26.6315676,4.81413617 L24.5599053,0.655603441 C24.3597524,0.253892444 23.949655,-8.95905326e-17 23.5009482,0 C23.0522413,5.97270217e-17 22.642144,0.253892444 22.441991,0.655603441 L20.3692531,4.81413617 L15.9796095,5.59850107 C15.5518938,5.67324058 15.1994617,5.97631422 15.0614174,6.38809939 C14.9233731,6.79988456 15.0218952,7.25422244 15.3180974,7.57178672 L18.4664647,10.9577899 L17.8114064,15.6489161 C17.7498225,16.0883409 17.9391303,16.5253075 18.3017873,16.7808292 C18.6644442,17.036351 19.1395182,17.0674963 19.5324134,16.8615077 L23.5004103,14.7913869 L27.4694829,16.8647355 C27.8623781,17.0707241 28.3374521,17.0395788 28.7001091,16.7840571 C29.062766,16.5285353 29.2520739,16.0915688 29.19049,15.652144 L28.534356,10.9577899 L31.6816477,7.57286266 C31.9779332,7.25540997 32.0766057,6.80113504 31.9387231,6.38932166 C31.8019739,5.98045861 31.4537759,5.67832329 31.0298163,5.60065296 Z" id="Shape" fill="#FF1AD9" fill-rule="nonzero"></path>
+        </g>
+    </g>
+</svg>
\ No newline at end of file
deleted file mode 100644
index 99d13992568063a9323ac793c22dbfb94fa0b572..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
GIT binary patch
literal 0
Hc$@<O00001
new file mode 100644
--- /dev/null
+++ b/browser/extensions/screenshots/webextension/icons/icon-welcome-face-without-eyes.svg
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 64 64" style="enable-background:new 0 0 64 64;" xml:space="preserve">
+<style type="text/css">
+	.st0{fill:#FFFFFF;}
+</style>
+<g id="Visual-design">
+	<g id="_x31_.2-Div-selection" transform="translate(-575.000000, -503.000000)">
+		<g id="Introduction" transform="translate(250.000000, 503.000000)">
+			<g id="icon-welcomeface" transform="translate(325.000000, 0.000000)">
+				<g id="Layer_1_1_">
+					<path id="Shape" class="st0" d="M11.4,0.9v2.9h-6c-0.9,0-1.5,0.8-1.5,1.5v6H0.8V3.8c0-1.7,1.4-3.1,3.1-3.1h7.6v0.2H11.4z"/>
+					<path id="Shape_1_" class="st0" d="M63.2,11.4h-3.1v-6c0-0.8-0.6-1.5-1.5-1.5h-6v-3h7.6c1.7,0,3.1,1.4,3.1,3.1L63.2,11.4
+						L63.2,11.4z"/>
+					<path id="Shape_2_" class="st0" d="M52.6,63.2v-3.1h6c0.9,0,1.5-0.6,1.5-1.5v-6h3.1v7.6c0,1.7-1.4,3.1-3.1,3.1L52.6,63.2
+						L52.6,63.2z"/>
+					<path id="Shape_3_" class="st0" d="M0.8,52.7h3.1v6c0,0.9,0.6,1.5,1.5,1.5h6v3.1H3.8c-1.7,0-3.1-1.4-3.1-3.1L0.8,52.7L0.8,52.7
+						z"/>
+					<path id="Shape_6_" class="st0" d="M33.3,49.2H33c-4.6-0.1-7.8-3.6-7.9-3.8c-0.6-0.8-0.6-2,0.1-2.7c0.8-0.8,1.9-0.6,2.6,0.1
+						c0,0,2.3,2.6,5.2,2.6c1.8,0,3.6-0.9,5.2-2.6c0.8-0.8,1.9-0.8,2.7,0s0.8,1.9,0,2.7C38.7,47.9,36,49.2,33.3,49.2z"/>
+				</g>
+			</g>
+		</g>
+	</g>
+</g>
+</svg>
--- a/browser/extensions/screenshots/webextension/icons/menu-myshot.svg
+++ b/browser/extensions/screenshots/webextension/icons/menu-myshot.svg
@@ -1,17 +1,1 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
-	 viewBox="0 0 46 46" style="enable-background:new 0 0 46 46;" xml:space="preserve">
-<style type="text/css">
-	.st0{fill:#3E3D40;}
-</style>
-<path class="st0" d="M11,29v6c0,0.5,0.4,1,1,1h6v-7H11z"/>
-<rect x="20" y="11" class="st0" width="7" height="7"/>
-<rect x="11" y="20" class="st0" width="7" height="7"/>
-<path class="st0" d="M18,11h-6c-0.5,0-1,0.4-1,1v6h7V11z"/>
-<rect x="20" y="29" class="st0" width="7" height="7"/>
-<path class="st0" d="M35,11h-6v7h7v-6C36,11.5,35.6,11,35,11z"/>
-<path class="st0" d="M29,36h6c0.5,0,1-0.4,1-1v-6h-7V36z"/>
-<rect x="20" y="20" class="st0" width="7" height="7"/>
-<rect x="29" y="20" class="st0" width="7" height="7"/>
-</svg>
+<svg width="46" height="46" viewBox="0 0 46 46" xmlns="http://www.w3.org/2000/svg"><title>Screenshots</title><path d="M11 11.995c0-.55.455-.995.995-.995h23.01c.55 0 .995.455.995.995v23.01c0 .55-.455.995-.995.995h-23.01c-.55 0-.995-.455-.995-.995v-23.01zM11 25v-2h7v2h-7zm9-5h7v-2h-7v2zm9 5h7v-2h-7v2zm-9 4h7v-2h-7v2zm-2-18h2v25h-2V11zm9 0h2v25h-2V11z" fill="#3E3D40" fill-rule="evenodd"/></svg>
index 7f0cc5c56af63fa32d980947a5058956b9f37718..3e7696f121b7fbe3e5a58cf6eefe57aedbb2fddb
GIT binary patch
literal 35808
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
--- a/browser/extensions/screenshots/webextension/log.js
+++ b/browser/extensions/screenshots/webextension/log.js
@@ -1,17 +1,17 @@
 /* globals buildSettings */
 
 "use strict";
 
-this.log = (function () {
+this.log = (function() {
   let exports = {};
 
   const levels = ["debug", "info", "warn", "error"];
-  if (! levels.includes(buildSettings.logLevel)) {
+  if (!levels.includes(buildSettings.logLevel)) {
     console.warn("Invalid buildSettings.logLevel:", buildSettings.logLevel);
   }
   let shouldLog = {};
 
   {
     let startLogging = false;
     for (let level of levels) {
       if (buildSettings.logLevel === level) {
--- a/browser/extensions/screenshots/webextension/makeUuid.js
+++ b/browser/extensions/screenshots/webextension/makeUuid.js
@@ -1,19 +1,19 @@
 "use strict";
 
-this.makeUuid = (function () {
+this.makeUuid = (function() {
 
   // generates a v4 UUID
   return function makeUuid() { // eslint-disable-line no-unused-vars
     // get sixteen unsigned 8 bit random values
     var randomValues = window
       .crypto
       .getRandomValues(new Uint8Array(36));
 
     return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
       var i = Array.prototype.slice.call(arguments).slice(-2)[0]; // grab the `offset` parameter
-      var r = randomValues[i]%16|0, v = c === 'x' ? r : (r&0x3|0x8);
+      var r = randomValues[i] % 16|0, v = c === 'x' ? r : (r & 0x3 | 0x8);
       return v.toString(16);
     });
   };
 })();
 null;
--- a/browser/extensions/screenshots/webextension/manifest.json
+++ b/browser/extensions/screenshots/webextension/manifest.json
@@ -1,12 +1,12 @@
 {
   "manifest_version": 2,
   "name": "Firefox Screenshots",
-  "version": "6.3.0",
+  "version": "6.6.0",
   "description": "__MSG_addonDescription__",
   "author": "__MSG_addonAuthorsList__",
   "homepage_url": "https://github.com/mozilla-services/screenshots",
   "applications": {
     "gecko": {
       "id": "screenshots@mozilla.org"
     }
   },
@@ -16,18 +16,18 @@
     "32": "icons/icon-32.png",
     "48": "icons/icon-48.png",
     "64": "icons/icon-64.png",
     "128": "icons/icon-128.png",
     "256": "icons/icon-256.png"
   },
   "browser_action": {
     "default_icon": {
-      "19": "icons/icon-19.png",
-      "38": "icons/icon-38.png"
+      "16": "icons/icon-16.svg",
+      "32": "icons/icon-32.svg"
     },
     "default_title": "__MSG_contextMenuLabel__",
     "browser_style": false
   },
   "background": {
     "scripts": [
       "build/buildSettings.js",
       "log.js",
@@ -59,24 +59,26 @@
     }
   ],
   "web_accessible_resources": [
     "blank.html",
     "icons/cancel.svg",
     "icons/download.svg",
     "icons/icon-256.png",
     "icons/back.svg",
+    "icons/back-highlight.svg",
     "icons/menu-fullpage.svg",
     "icons/menu-visible.svg",
     "icons/menu-myshot.svg",
     "icons/onboarding-1.png",
     "icons/onboarding-2.png",
     "icons/onboarding-3.png",
     "icons/onboarding-4.png",
-    "icons/done.svg"
+    "icons/done.svg",
+    "icons/icon-welcome-face-without-eyes.svg"
   ],
   "permissions": [
     "activeTab",
     "downloads",
     "tabs",
     "storage",
     "notifications",
     "clipboardWrite",
--- a/browser/extensions/screenshots/webextension/onboarding/slides.html
+++ b/browser/extensions/screenshots/webextension/onboarding/slides.html
@@ -39,19 +39,19 @@
           <div class="slide-content">
             <h1 data-l10n-id="tourHeaderFour"></h1>
             <p data-l10n-id="tourBodyFour"></p>
           </div>
         </div>
 
         <!-- Clickable elements should be buttons for accessibility -->
         <button id="skip" data-l10n-id="tourSkip" tabindex=1>Skip</button>
-        <button id="prev" tabindex=2 data-l10n-label-id="tourPrevious" style="background-image: url('MOZ_EXTENSION/icons/back.svg');"></button>
-        <button id="next" tabindex=3 data-l10n-label-id="tourNext" style="background-image: url('MOZ_EXTENSION/icons/back.svg');"/></button>
-        <button id="done" tabindex=4 data-l10n-label-id="tourDone" style="background-image: url('MOZ_EXTENSION/icons/done.svg')"></button>
+        <button id="prev" tabindex=2 data-l10n-label-id="tourPrevious"></button>
+        <button id="next" tabindex=3 data-l10n-label-id="tourNext"></button>
+        <button id="done" tabindex=4 data-l10n-label-id="tourDone"></button>
         <div id="slide-status-container">
           <button class="goto-slide goto-slide-1" data-number="1" tabindex=4></button>
           <button class="goto-slide goto-slide-2" data-number="2" tabindex=5></button>
           <button class="goto-slide goto-slide-3" data-number="3" tabindex=6></button>
           <button class="goto-slide goto-slide-4" data-number="4" tabindex=7></button>
         </div>
         <!-- FIXME: Need to put in privacy / etc links -->
       </div>
--- a/browser/extensions/screenshots/webextension/onboarding/slides.js
+++ b/browser/extensions/screenshots/webextension/onboarding/slides.js
@@ -1,25 +1,24 @@
-/* globals catcher, onboardingHtml, onboardingCss, browser, util, shooter, callBackground, assertIsTrusted */
+/* globals log, catcher, onboardingHtml, onboardingCss, browser, util, shooter, callBackground, assertIsTrusted */
 
 "use strict";
 
-this.slides = (function () {
+this.slides = (function() {
   let exports = {};
 
   const { watchFunction } = catcher;
 
   let iframe;
   let doc;
   let currentSlide = 1;
   let numberOfSlides;
   let callbacks;
-  let backend;
 
-  exports.display = function (addCallbacks) {
+  exports.display = function(addCallbacks) {
     if (iframe) {
       throw new Error("Attemted to call slides.display() twice");
     }
     return new Promise((resolve, reject) => {
       callbacks = addCallbacks;
       // FIXME: a lot of this iframe logic is in ui.js; maybe move to util.js
       iframe = document.createElement("iframe");
       iframe.src = browser.extension.getURL("blank.html");
@@ -41,36 +40,31 @@ this.slides = (function () {
           html,
           "text/html"
         );
         doc = iframe.contentDocument;
         doc.replaceChild(
           doc.adoptNode(parsedDom.documentElement),
           doc.documentElement
         );
-        doc.addEventListener("keyup", onKeyUp, false);
-        callBackground("getBackend").then((backendResult) => {
-          backend = backendResult;
-          localizeText(doc);
-          activateSlide(doc);
-          resolve();
-        }).catch((error) => {
-          // Handled in communication.js
-        });
+        doc.addEventListener("keyup", onKeyUp);
+        localizeText(doc);
+        activateSlide(doc);
+        resolve();
       });
       document.body.appendChild(iframe);
       iframe.focus();
-      window.addEventListener("resize", onResize, false);
+      window.addEventListener("resize", onResize);
     });
   };
 
-  exports.remove = exports.unload = function () {
-    window.removeEventListener("resize", onResize, false);
+  exports.remove = exports.unload = function() {
+    window.removeEventListener("resize", onResize);
     if (doc) {
-      doc.removeEventListener("keyup", onKeyUp, false);
+      doc.removeEventListener("keyup", onKeyUp);
     }
     util.removeNode(iframe);
     iframe = doc = null;
     currentSlide = 1;
     numberOfSlides = undefined;
     callbacks = undefined;
   };
 
@@ -82,117 +76,136 @@ this.slides = (function () {
       el.textContent = text;
     }
     els = doc.querySelectorAll("[data-l10n-label-id]");
     for (let el of els) {
       let id = el.getAttribute("data-l10n-label-id");
       let text = browser.i18n.getMessage(id);
       el.setAttribute("aria-label", text);
     }
-    // termsAndPrivacyNotice is a more complicated substitution:
+    // termsAndPrivacyNoticeCloudServices is a more complicated substitution:
     let termsContainer = doc.querySelector(".onboarding-legal-notice");
     termsContainer.innerHTML = "";
-    let termsSentinal = "__TERMS__";
-    let privacySentinal = "__PRIVACY__";
-    let sentinalSplitter = "!!!";
+    let termsSentinel = "__TERMS__";
+    let privacySentinel = "__PRIVACY__";
+    let sentinelSplitter = "!!!";
     let linkTexts = {
-      [termsSentinal]: browser.i18n.getMessage("termsAndPrivacyNoticeTermsLink"),
-      [privacySentinal]: browser.i18n.getMessage("termsAndPrivacyNoticyPrivacyLink")
+      [termsSentinel]: browser.i18n.getMessage("termsAndPrivacyNoticeTermsLink"),
+      [privacySentinel]: browser.i18n.getMessage("termsAndPrivacyNoticyPrivacyLink")
     };
     let linkUrls = {
-      [termsSentinal]: "https://www.mozilla.org/about/legal/terms/services/",
-      [privacySentinal]: "https://www.mozilla.org/privacy/firefox-cloud/"
+      [termsSentinel]: "https://www.mozilla.org/about/legal/terms/services/",
+      [privacySentinel]: "https://www.mozilla.org/privacy/firefox-cloud/"
     };
     let text = browser.i18n.getMessage(
-      "termsAndPrivacyNotice",
-      [sentinalSplitter + termsSentinal + sentinalSplitter,
-       sentinalSplitter + privacySentinal + sentinalSplitter]);
-    let parts = text.split(sentinalSplitter);
+      "termsAndPrivacyNoticeCloudServices",
+      [sentinelSplitter + termsSentinel + sentinelSplitter,
+       sentinelSplitter + privacySentinel + sentinelSplitter]);
+    let parts = text.split(sentinelSplitter);
     for (let part of parts) {
       let el;
-      if (part === termsSentinal || part === privacySentinal) {
+      if (part === termsSentinel || part === privacySentinel) {
         el = doc.createElement("a");
         el.href = linkUrls[part];
         el.textContent = linkTexts[part];
         el.target = "_blank";
+        el.id = (part === termsSentinel) ? "terms" : "privacy";
       } else {
         el = doc.createTextNode(part);
       }
       termsContainer.appendChild(el);
     }
   }
 
   function activateSlide(doc) {
     numberOfSlides = parseInt(doc.querySelector("[data-number-of-slides]").getAttribute("data-number-of-slides"), 10);
     doc.querySelector("#next").addEventListener("click", watchFunction(assertIsTrusted(() => {
       shooter.sendEvent("navigate-slide", "next");
       next();
-    })), false);
+    })));
     doc.querySelector("#prev").addEventListener("click", watchFunction(assertIsTrusted(() => {
       shooter.sendEvent("navigate-slide", "prev");
       prev();
-    })), false);
+    })));
     for (let el of doc.querySelectorAll(".goto-slide")) {
       el.addEventListener("click", watchFunction(assertIsTrusted((event) => {
         shooter.sendEvent("navigate-slide", "goto");
         let el = event.target;
         let index = parseInt(el.getAttribute("data-number"), 10);
         setSlide(index);
-      })), false);
+      })));
     }
     doc.querySelector("#skip").addEventListener("click", watchFunction(assertIsTrusted((event) => {
       shooter.sendEvent("cancel-slides", "skip");
       callbacks.onEnd();
-    })), false);
+    })));
     doc.querySelector("#done").addEventListener("click", watchFunction(assertIsTrusted((event) => {
       shooter.sendEvent("finish-slides", "done");
       callbacks.onEnd();
-    })), false);
+    })));
+    // Note: e10s breaks the terms and privacy anchor tags. Work around this by
+    // manually opening the correct URLs on click until bug 1357589 is fixed.
+    doc.querySelector("#terms").addEventListener("click", watchFunction(assertIsTrusted((event) => {
+      event.preventDefault();
+      callBackground("openTermsPage");
+    })));
+    doc.querySelector("#privacy").addEventListener("click", watchFunction(assertIsTrusted((event) => {
+      event.preventDefault();
+      callBackground("openPrivacyPage");
+    })));
     setSlide(1);
   }
 
   function next() {
     setSlide(currentSlide + 1);
   }
 
   function prev() {
     setSlide(currentSlide - 1);
   }
 
-  const onResize = catcher.watchFunction(function () {
-    if (! iframe) {
+  const onResize = catcher.watchFunction(function() {
+    if (!iframe) {
       log.warn("slides onResize called when iframe is not setup");
       return;
     }
     updateIframeSize();
   });
 
   function updateIframeSize() {
     iframe.style.height = window.innerHeight + "px";
     iframe.style.width = window.innerWidth + "px";
   }
 
-  const onKeyUp = catcher.watchFunction(assertIsTrusted(function (event) {
+  const onKeyUp = catcher.watchFunction(assertIsTrusted(function(event) {
     if ((event.key || event.code) === "Escape") {
       shooter.sendEvent("cancel-slides", "keyboard-escape");
       callbacks.onEnd();
     }
+    if ((event.key || event.code) === "ArrowRight") {
+      shooter.sendEvent("navigate-slide", "keyboard-arrowright");
+      next();
+    }
+    if ((event.key || event.code) === "ArrowLeft") {
+      shooter.sendEvent("navigate-slide", "keyboard-arrowleft");
+      prev();
+    }
   }));
 
   function setSlide(index) {
     if (index < 1) {
       index = 1;
     }
     if (index > numberOfSlides) {
       index = numberOfSlides;
     }
     shooter.sendEvent("visited-slide", `slide-${index}`);
     currentSlide = index;
     let slideEl = doc.querySelector("#slide-container");
-    for (let i=1; i<=numberOfSlides; i++) {
+    for (let i = 1; i <= numberOfSlides; i++) {
       let className = `active-slide-${i}`;
       if (i == currentSlide) {
         slideEl.classList.add(className);
       } else {
         slideEl.classList.remove(className);
       }
     }
   }
--- a/browser/extensions/screenshots/webextension/randomString.js
+++ b/browser/extensions/screenshots/webextension/randomString.js
@@ -1,14 +1,14 @@
 /* exported randomString */
 
 "use strict";
 
 this.randomString = function randomString(length, chars) {
   let randomStringChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
   chars = chars || randomStringChars;
   let result = "";
-  for (let i=0; i<length; i++) {
+  for (let i = 0; i < length; i++) {
     result += chars[Math.floor(Math.random() * chars.length)]
   }
   return result;
 }
 null;
--- a/browser/extensions/screenshots/webextension/selector/callBackground.js
+++ b/browser/extensions/screenshots/webextension/selector/callBackground.js
@@ -1,19 +1,25 @@
 /* globals browser, log */
 
 "use strict";
 
-this.callBackground = function callBackground (funcName, ...args) {
+this.callBackground = function callBackground(funcName, ...args) {
   return browser.runtime.sendMessage({funcName, args}).then((result) => {
     if (result.type === "success") {
       return result.value;
     } else if (result.type === "error") {
       let exc = new Error(result.message);
       exc.name = "BackgroundError";
+      if ('errorCode' in result) {
+        exc.errorCode = result.errorCode;
+      }
+      if ('popupMessage' in result) {
+        exc.popupMessage = result.popupMessage;
+      }
       throw exc;
     } else {
       log.error("Unexpected background result:", result);
       let exc = new Error(`Bad response type from background page: ${result.type || undefined}`);
       exc.resultType = result.type || "undefined";
       throw exc;
     }
   });
--- a/browser/extensions/screenshots/webextension/selector/documentMetadata.js
+++ b/browser/extensions/screenshots/webextension/selector/documentMetadata.js
@@ -1,11 +1,11 @@
 "use strict";
 
-this.documentMetadata = (function () {
+this.documentMetadata = (function() {
 
   function findSiteName() {
     let el = document.querySelector("meta[property='og:site_name']");
     if (el) {
       return el.getAttribute("content");
     }
     // nytimes.com uses this property:
     el = document.querySelector("meta[name='cre']");
@@ -37,17 +37,17 @@ this.documentMetadata = (function () {
       if (elems.length > 1) {
         value = [];
         for (let elem of elems) {
           let v = elem.getAttribute("content");
           if (v) {
             value.push(v);
           }
         }
-        if (! value.length) {
+        if (!value.length) {
           value = null;
         }
       } else if (elems.length === 1) {
         value = elems[0].getAttribute("content");
       }
       if (value) {
         openGraph[prop] = value;
       }
--- a/browser/extensions/screenshots/webextension/selector/shooter.js
+++ b/browser/extensions/screenshots/webextension/selector/shooter.js
@@ -1,22 +1,24 @@
-/* globals callBackground, documentMetadata, uicontrol, util, ui, catcher */
-/* globals XMLHttpRequest, window, location, alert, console, domainFromUrl, randomString */
-/* globals clipboard, document, setTimeout, location */
+/* globals global, documentMetadata, util, uicontrol, ui, catcher */
+/* globals XMLHttpRequest, window, location, alert, domainFromUrl, randomString */
+/* globals document, setTimeout, location */
 
 "use strict";
 
-this.shooter = (function () { // eslint-disable-line no-unused-vars
+this.shooter = (function() { // eslint-disable-line no-unused-vars
   let exports = {};
   const { AbstractShot } = window.shot;
 
   const RANDOM_STRING_LENGTH = 16;
   let backend;
   let shot;
   let supportsDrawWindow;
+  const callBackground = global.callBackground;
+  const clipboard = global.clipboard;
 
   function regexpEscape(str) {
     // http://stackoverflow.com/questions/3115150/how-to-escape-regular-expression-special-characters-using-javascript
     return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
   }
 
   function sanitizeError(data) {
     const href = new RegExp(regexpEscape(window.location.href), 'g');
@@ -30,21 +32,21 @@ this.shooter = (function () { // eslint-
 
   catcher.registerHandler((errorObj) => {
     callBackground("reportError", sanitizeError(errorObj));
   });
 
   {
     let canvas = document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
     let ctx = canvas.getContext('2d');
-    supportsDrawWindow = !! ctx.drawWindow;
+    supportsDrawWindow = !!ctx.drawWindow;
   }
 
   function screenshotPage(selectedPos) {
-    if (! supportsDrawWindow) {
+    if (!supportsDrawWindow) {
       return null;
     }
     let height = selectedPos.bottom - selectedPos.top;
     let width = selectedPos.right - selectedPos.left;
     let canvas = document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
     canvas.width = width * window.devicePixelRatio;
     canvas.height = height * window.devicePixelRatio;
     let ctx = canvas.getContext('2d');
@@ -57,20 +59,22 @@ this.shooter = (function () { // eslint-
     } finally {
       ui.iframe.unhide();
     }
     return canvas.toDataURL();
   }
 
   let isSaving = null;
 
-  exports.takeShot = function (captureType, selectedPos) {
+  exports.takeShot = function(captureType, selectedPos) {
     // isSaving indicates we're aleady in the middle of saving
     // we use a timeout so in the case of a failure the button will
     // still start working again
+    const uicontrol = global.uicontrol;
+    let deactivateAfterFinish = true;
     if (isSaving) {
       return;
     }
     isSaving = setTimeout(() => {
       isSaving = null;
     }, 1000);
     selectedPos = selectedPos.asJson();
     let captureText = util.captureEnclosedText(selectedPos);
@@ -101,44 +105,54 @@ this.shooter = (function () { // eslint-
       },
       selectedPos,
       shotId: shot.id,
       shot: shot.asJson()
     }).then((url) => {
       const copied = clipboard.copy(url);
       return callBackground("openShot", { url, copied });
     }, (error) => {
+      if ('popupMessage' in error && (error.popupMessage == "REQUEST_ERROR" || error.popupMessage == 'CONNECTION_ERROR')) {
+        // The error has been signaled to the user, but unlike other errors (or
+        // success) we should not abort the selection
+        deactivateAfterFinish = false;
+        return;
+      }
       if (error.name != "BackgroundError") {
         // BackgroundError errors are reported in the Background page
         throw error;
       }
-    }).then(() => uicontrol.deactivate()));
+    }).then(() => {
+      if (deactivateAfterFinish) {
+        uicontrol.deactivate();
+      }
+    }));
   };
 
-  exports.downloadShot = function (selectedPos) {
+  exports.downloadShot = function(selectedPos) {
     let dataUrl = screenshotPage(selectedPos);
     let promise = Promise.resolve(dataUrl);
-    if (! dataUrl) {
+    if (!dataUrl) {
       promise = callBackground(
         "screenshotPage",
         selectedPos.asJson(),
         {
           scrollX: window.scrollX,
           scrollY: window.scrollY,
           innerHeight: window.innerHeight,
           innerWidth: window.innerWidth
         });
     }
     catcher.watchPromise(promise.then((dataUrl) => {
       ui.triggerDownload(dataUrl, shot.filename);
       uicontrol.deactivate();
     }));
   };
 
-  exports.sendEvent = function (...args) {
+  exports.sendEvent = function(...args) {
     callBackground("sendEvent", ...args);
   };
 
   shot = new AbstractShot(
     backend,
     randomString(RANDOM_STRING_LENGTH) + "/" + domainFromUrl(location),
     {
       origin: window.shot.originFromUrl(location.href)
--- a/browser/extensions/screenshots/webextension/selector/ui.js
+++ b/browser/extensions/screenshots/webextension/selector/ui.js
@@ -1,14 +1,14 @@
-/* globals window, document, console, browser */
-/* globals util, catcher, inlineSelectionCss, callBackground, assertIsTrusted */
+/* globals window, document, browser */
+/* globals log, util, catcher, inlineSelectionCss, callBackground, assertIsTrusted */
 
 "use strict";
 
-this.ui = (function () { // eslint-disable-line no-unused-vars
+this.ui = (function() { // eslint-disable-line no-unused-vars
   let exports = {};
   const SAVE_BUTTON_HEIGHT = 50;
 
   const { watchFunction } = catcher;
 
   // The <body> tag itself can have margins and offsets, which need to be used when
   // setting the position of the boxEl.
   function getBodyRect() {
@@ -26,17 +26,17 @@ this.ui = (function () { // eslint-disab
     // *not* necessary on http://patriciogonzalezvivo.com/2015/thebookofshaders/
     // (actually causes mis-selection there)
     // *is* necessary on http://atirip.com/2015/03/17/sorry-sad-state-of-matrix-transforms-in-browsers/
     cached = {top: 0, bottom: 0, left: 0, right: 0};
     getBodyRect.cached = cached;
     return cached;
   }
 
-  exports.isHeader = function (el) {
+  exports.isHeader = function(el) {
     while (el) {
       if (el.classList &&
           (el.classList.contains("myshots-button") ||
            el.classList.contains("visible") ||
            el.classList.contains("full-page"))) {
         return true;
       }
       el = el.parentNode;
@@ -44,17 +44,17 @@ this.ui = (function () { // eslint-disab
     return false;
   }
 
   let substitutedCss = inlineSelectionCss.replace(/MOZ_EXTENSION([^\"]+)/g, (match, filename) => {
     return browser.extension.getURL(filename);
   });
 
   function makeEl(tagName, className) {
-    if (! iframe.document()) {
+    if (!iframe.document()) {
       throw new Error("Attempted makeEl before iframe was initialized");
     }
     let el = iframe.document().createElement(tagName);
     if (className) {
       el.className = className;
     }
     return el;
   }
@@ -73,19 +73,19 @@ this.ui = (function () { // eslint-disab
     addClassName: "",
     sizeTracking: {
       timer: null,
       windowDelayer: null,
       lastHeight: null,
       lastWidth: null
     },
     document: null,
-    display: function (installHandlerOnDocument) {
+    display(installHandlerOnDocument) {
       return new Promise((resolve, reject) => {
-        if (! this.element) {
+        if (!this.element) {
           this.element = document.createElement("iframe");
           this.element.src = browser.extension.getURL("blank.html");
           this.element.id = "firefox-screenshots-selection-iframe";
           this.element.style.display = "none";
           this.element.style.zIndex = "99999999999";
           this.element.style.border = "none";
           this.element.style.position = "absolute";
           this.element.style.top = "0";
@@ -109,29 +109,29 @@ this.ui = (function () { // eslint-disab
           });
           document.body.appendChild(this.element);
         } else {
           resolve();
         }
       });
     },
 
-    hide: function () {
+    hide() {
       this.element.style.display = "none";
       this.stopSizeWatch();
     },
 
-    unhide: function () {
+    unhide() {
       this.updateElementSize();
       this.element.style.display = "";
       this.initSizeWatch();
       this.element.focus();
     },
 
-    updateElementSize: function (force) {
+    updateElementSize(force) {
       // Note: if someone sizes down the page, then the iframe will keep the
       // document from naturally shrinking.  We use force to temporarily hide
       // the element so that we can tell if the document shrinks
       const visible = this.element.style.display !== "none";
       if (force && visible) {
         this.element.style.display = "none";
       }
       let height = Math.max(
@@ -154,85 +154,90 @@ this.ui = (function () { // eslint-disab
         this.sizeTracking.lastWidth = width;
         this.element.style.width = width + "px";
       }
       if (force && visible) {
         this.element.style.display = "";
       }
     },
 
-    initSizeWatch: function () {
+    initSizeWatch() {
       this.stopSizeWatch();
       this.sizeTracking.timer = setInterval(watchFunction(this.updateElementSize.bind(this)), 2000);
       window.addEventListener("resize", this.onResize, true);
     },
 
-    stopSizeWatch: function () {
+    stopSizeWatch() {
       if (this.sizeTracking.timer) {
         clearTimeout(this.sizeTracking.timer);
         this.sizeTracking.timer = null;
       }
       if (this.sizeTracking.windowDelayer) {
         clearTimeout(this.sizeTracking.windowDelayer);
         this.sizeTracking.windowDelayer = null;
       }
       this.sizeTracking.lastHeight = this.sizeTracking.lastWidth = null;
       window.removeEventListener("resize", this.onResize, true);
     },
 
-    getElementFromPoint: function (x, y) {
+    getElementFromPoint(x, y) {
       this.element.style.pointerEvents = "none";
       let el;
       try {
         el = document.elementFromPoint(x, y);
       } finally {
         this.element.style.pointerEvents = "";
       }
       return el;
     },
 
-    remove: function () {
+    remove() {
       this.stopSizeWatch();
       util.removeNode(this.element);
       this.element = this.document = null;
     }
   };
 
   iframeSelection.onResize = watchFunction(onResize.bind(iframeSelection));
 
   let iframePreSelection = exports.iframePreSelection = {
     element: null,
     document: null,
     sizeTracking: {
       windowDelayer: null
     },
-    display: function (installHandlerOnDocument, standardOverlayCallbacks) {
+    display(installHandlerOnDocument, standardOverlayCallbacks) {
       return new Promise((resolve, reject) => {
-        if (! this.element) {
+        if (!this.element) {
           this.element = document.createElement("iframe");
           this.element.src = browser.extension.getURL("blank.html");
           this.element.id = "firefox-screenshots-preselection-iframe";
           this.element.style.zIndex = "99999999999";
           this.element.style.border = "none";
           this.element.style.position = "fixed";
           this.element.style.top = "0";
           this.element.style.left = "0";
           this.element.style.margin = "0";
           this.element.scrolling = "no";
           this.updateElementSize();
           this.element.onload = watchFunction(() => {
             this.document = this.element.contentDocument;
-            this.document.documentElement.innerHTML= `
+            this.document.documentElement.innerHTML = `
                <head>
                 <style>${substitutedCss}</style>
                 <title></title>
                </head>
                <body>
                  <div class="preview-overlay">
                    <div class="fixed-container">
+                     <div class="face-container">
+                       <div class="eye left"><div class="eyeball"></div></div>
+                       <div class="eye right"><div class="eyeball"></div></div>
+                       <div class="face"></div>
+                     </div>
                      <div class="preview-instructions"></div>
                      <div class="myshots-all-buttons-container">
                        <button class="myshots-button myshots-link" tabindex="1"></button>
                        <div class="spacer"></div>
                        <button class="myshots-button visible" tabindex="2"></button>
                        <button class="myshots-button full-page" tabindex="3"></button>
                      </div>
                    </div>
@@ -243,128 +248,128 @@ this.ui = (function () { // eslint-disab
               this.document.body.className = this.addClassName;
             }
             const overlay = this.document.querySelector(".preview-overlay");
             overlay.querySelector(".preview-instructions").textContent = browser.i18n.getMessage("screenshotInstructions");
             overlay.querySelector(".myshots-link").textContent = browser.i18n.getMessage("myShotsLink");
             overlay.querySelector(".visible").textContent = browser.i18n.getMessage("saveScreenshotVisibleArea");
             overlay.querySelector(".full-page").textContent = browser.i18n.getMessage("saveScreenshotFullPage");
             overlay.querySelector(".myshots-button").addEventListener(
-              "click", watchFunction(assertIsTrusted(standardOverlayCallbacks.onOpenMyShots)), false);
+              "click", watchFunction(assertIsTrusted(standardOverlayCallbacks.onOpenMyShots)));
             overlay.querySelector(".visible").addEventListener(
-              "click", watchFunction(assertIsTrusted(standardOverlayCallbacks.onClickVisible)), false);
+              "click", watchFunction(assertIsTrusted(standardOverlayCallbacks.onClickVisible)));
             overlay.querySelector(".full-page").addEventListener(
-              "click", watchFunction(assertIsTrusted(standardOverlayCallbacks.onClickFullPage)), false);
+              "click", watchFunction(assertIsTrusted(standardOverlayCallbacks.onClickFullPage)));
             resolve();
           });
           document.body.appendChild(this.element);
           this.unhide();
         } else {
           resolve();
         }
       });
     },
 
-    updateElementSize: function () {
+    updateElementSize() {
       this.element.style.height = window.innerHeight + "px";
       this.element.style.width = window.innerWidth + "px";
     },
 
-    hide: function () {
-      window.removeEventListener("scroll", this.onScroll, false);
+    hide() {
+      window.removeEventListener("scroll", this.onScroll);
       window.removeEventListener("resize", this.onResize, true);
       if (this.element) {
         this.element.style.display = "none";
       }
     },
 
-    unhide: function () {
+    unhide() {
       this.updateElementSize();
-      window.addEventListener("scroll", this.onScroll, false);
+      window.addEventListener("scroll", this.onScroll);
       window.addEventListener("resize", this.onResize, true);
       this.element.style.display = "";
       this.element.focus();
     },
 
-    onScroll: function () {
+    onScroll() {
       exports.HoverBox.hide();
     },
 
-    getElementFromPoint: function (x, y) {
+    getElementFromPoint(x, y) {
       this.element.style.pointerEvents = "none";
       let el;
       try {
         el = document.elementFromPoint(x, y);
       } finally {
         this.element.style.pointerEvents = "";
       }
       return el;
     },
 
-    remove: function () {
+    remove() {
       this.hide();
       util.removeNode(this.element);
       this.element = null;
       this.document = null;
     }
   };
 
   iframePreSelection.onResize = watchFunction(onResize.bind(iframePreSelection));
 
   let iframe = exports.iframe = {
     currentIframe: iframePreSelection,
-    display: function (installHandlerOnDocument, standardOverlayCallbacks) {
+    display(installHandlerOnDocument, standardOverlayCallbacks) {
       return iframeSelection.display(installHandlerOnDocument)
         .then(() => iframePreSelection.display(installHandlerOnDocument, standardOverlayCallbacks));
     },
 
-    hide: function () {
+    hide() {
       this.currentIframe.hide();
     },
 
-    unhide: function () {
+    unhide() {
       this.currentIframe.unhide();
     },
 
-    getElementFromPoint: function (x, y) {
+    getElementFromPoint(x, y) {
       return this.currentIframe.getElementFromPoint(x, y);
     },
 
-    remove: function () {
+    remove() {
       iframeSelection.remove();
       iframePreSelection.remove();
     },
 
-    document: function () {
+    document() {
       return this.currentIframe.document;
     },
 
-    useSelection: function () {
+    useSelection() {
       if (this.currentIframe === iframePreSelection) {
         this.hide();
       }
       this.currentIframe = iframeSelection;
       this.unhide();
     },
 
-    usePreSelection: function () {
+    usePreSelection() {
       if (this.currentIframe === iframeSelection) {
         this.hide();
       }
       this.currentIframe = iframePreSelection;
       this.unhide();
     }
   };
 
   let movements = ["topLeft", "top", "topRight", "left", "right", "bottomLeft", "bottom", "bottomRight"];
 
   /** Creates the selection box */
   exports.Box = {
 
-    display: function (pos, callbacks) {
+    display(pos, callbacks) {
       this._createEl();
       if (callbacks !== undefined && callbacks.cancel) {
         // We use onclick here because we don't want addEventListener
         // to add multiple event handlers to the same button
         this.cancel.onclick = watchFunction(assertIsTrusted(callbacks.cancel));
         this.cancel.style.display = "";
       } else {
         this.cancel.style.display = "none";
@@ -410,48 +415,55 @@ this.ui = (function () { // eslint-disab
 
       // if the selection bounding box is w/in SAVE_BUTTON_HEIGHT px of the bottom of
       // the window, flip controls into the box
       if (pos.bottom > ((winBottom + pageYOffset) - SAVE_BUTTON_HEIGHT)) {
         this.el.classList.add("bottom-selection");
       } else {
         this.el.classList.remove("bottom-selection");
       }
+
+      if (pos.right < 200) {
+        this.el.classList.add("left-selection");
+      } else {
+        this.el.classList.remove("left-selection");
+      }
+
       this.el.style.top = (pos.top - bodyRect.top) + "px";
       this.el.style.left = (pos.left - bodyRect.left) + "px";
       this.el.style.height = (pos.bottom - pos.top - bodyRect.top) + "px";
       this.el.style.width = (pos.right - pos.left - bodyRect.left) + "px";
       this.bgTop.style.top = "0px";
       this.bgTop.style.height = (pos.top - bodyRect.top) + "px";
       this.bgTop.style.left = "0px";
       this.bgTop.style.width = docWidth + "px";
       this.bgBottom.style.top = (pos.bottom - bodyRect.top) + "px";
       this.bgBottom.style.height = docHeight - (pos.bottom - bodyRect.top) + "px";
       this.bgBottom.style.left = "0px";
       this.bgBottom.style.width = docWidth + "px";
       this.bgLeft.style.top = (pos.top - bodyRect.top) + "px";
-      this.bgLeft.style.height = pos.bottom - pos.top  + "px";
+      this.bgLeft.style.height = pos.bottom - pos.top + "px";
       this.bgLeft.style.left = "0px";
       this.bgLeft.style.width = (pos.left - bodyRect.left) + "px";
       this.bgRight.style.top = (pos.top - bodyRect.top) + "px";
       this.bgRight.style.height = pos.bottom - pos.top + "px";
       this.bgRight.style.left = (pos.right - bodyRect.left) + "px";
       this.bgRight.style.width = docWidth - (pos.right - bodyRect.left) + "px";
     },
 
-    remove: function () {
+    remove() {
       for (let name of ["el", "bgTop", "bgLeft", "bgRight", "bgBottom"]) {
         if (name in this) {
           util.removeNode(this[name]);
           this[name] = null;
         }
       }
     },
 
-    _createEl: function () {
+    _createEl() {
       let boxEl = this.el;
       if (boxEl) {
         return;
       }
       boxEl = makeEl("div", "highlight");
       let buttons = makeEl("div", "highlight-buttons");
       let cancel = makeEl("button", "highlight-button-cancel");
       cancel.title = browser.i18n.getMessage("cancelScreenshot");
@@ -480,17 +492,17 @@ this.ui = (function () { // eslint-disab
       this.bgRight = makeEl("div", "bghighlight");
       iframe.document().body.appendChild(this.bgRight);
       this.bgBottom = makeEl("div", "bghighlight");
       iframe.document().body.appendChild(this.bgBottom);
       iframe.document().body.appendChild(boxEl);
       this.el = boxEl;
     },
 
-    draggerDirection: function (target) {
+    draggerDirection(target) {
       while (target) {
         if (target.nodeType == document.ELEMENT_NODE) {
           if (target.classList.contains("mover-target")) {
             for (let name of movements) {
               if (target.classList.contains("direction-" + name)) {
                 return name;
               }
             }
@@ -498,30 +510,30 @@ this.ui = (function () { // eslint-disab
             log.warn("Got mover-target that wasn't a specific direction");
           }
         }
         target = target.parentNode;
       }
       return null;
     },
 
-    isSelection: function (target) {
+    isSelection(target) {
       while (target) {
         if (target.tagName === "BUTTON") {
           return false;
         }
         if (target.nodeType == document.ELEMENT_NODE && target.classList.contains("highlight")) {
           return true;
         }
         target = target.parentNode;
       }
       return false;
     },
 
-    isControl: function (target) {
+    isControl(target) {
       while (target) {
         if (target.nodeType === document.ELEMENT_NODE && target.classList.contains("highlight-buttons")) {
           return true;
         }
         target = target.parentNode;
       }
       return false;
     },
@@ -532,78 +544,78 @@ this.ui = (function () { // eslint-disab
     boxRightEl: null,
     boxBottomEl: null
   };
 
   exports.HoverBox = {
 
     el: null,
 
-    display: function (rect) {
-      if (! this.el) {
+    display(rect) {
+      if (!this.el) {
         this.el = makeEl("div", "hover-highlight");
         iframe.document().body.appendChild(this.el);
       }
       this.el.style.display = "";
       this.el.style.top = (rect.top - 1) + "px";
       this.el.style.left = (rect.left - 1) + "px";
       this.el.style.width = (rect.right - rect.left + 2) + "px";
       this.el.style.height = (rect.bottom - rect.top + 2) + "px";
     },
 
-    hide: function () {
+    hide() {
       if (this.el) {
         this.el.style.display = "none";
       }
     },
 
-    remove: function () {
+    remove() {
       util.removeNode(this.el);
       this.el = null;
     }
   };
 
   exports.PixelDimensions = {
     el: null,
     xEl: null,
     yEl: null,
-    display: function (xPos, yPos, x, y) {
-      if (! this.el) {
+    display(xPos, yPos, x, y) {
+      if (!this.el) {
         this.el = makeEl("div", "pixel-dimensions");
         this.xEl = makeEl("div");
         this.el.appendChild(this.xEl);
         this.yEl = makeEl("div");
         this.el.appendChild(this.yEl);
         iframe.document().body.appendChild(this.el);
       }
       this.xEl.textContent = x;
       this.yEl.textContent = y;
       this.el.style.top = (yPos + 12) + "px";
       this.el.style.left = (xPos + 12) + "px";
     },
-    remove: function () {
+    remove() {
       util.removeNode(this.el);
       this.el = this.xEl = this.yEl = null;
     }
   };
 
   /** Removes every UI this module creates */
-  exports.remove = function () {
+  exports.remove = function() {
     for (let name in exports) {
       if (name.startsWith("iframe")) {
         continue;
       }
       if (typeof exports[name] == "object" && exports[name].remove) {
         exports[name].remove();
       }
     }
     exports.iframe.remove();
   };
 
-  exports.triggerDownload = function (url, filename) {
+  exports.triggerDownload = function(url, filename) {
     return catcher.watchPromise(callBackground("downloadShot", {url, filename}));
   };
 
   exports.unload = exports.remove;
 
   return exports;
 })();
 null;
--- a/browser/extensions/screenshots/webextension/selector/uicontrol.js
+++ b/browser/extensions/screenshots/webextension/selector/uicontrol.js
@@ -1,17 +1,17 @@
-/* globals console, catcher, util, ui, slides */
+/* globals log, catcher, util, ui, slides */
 /* globals window, document, location, shooter, callBackground, selectorLoader, assertIsTrusted */
 
 "use strict";
 
-this.uicontrol = (function () {
+this.uicontrol = (function() {
   let exports = {};
 
-  /**********************************************************
+  /** ********************************************************
    * selection
    */
 
   /* States:
 
   "crosshairs":
     Nothing has happened, and the crosshairs will follow the movement of the mouse
   "draggingReady":
@@ -52,18 +52,22 @@ this.uicontrol = (function () {
   const MIN_DETECT_HEIGHT = 30;
   const MIN_DETECT_WIDTH = 100;
   // An autoselection bigger than either of these will be ignored:
   const MAX_DETECT_HEIGHT = Math.max(window.innerHeight + 100, 700);
   const MAX_DETECT_WIDTH = Math.max(window.innerWidth + 100, 1000);
   // This is how close (in pixels) you can get to the edge of the window and then
   // it will scroll:
   const SCROLL_BY_EDGE = 20;
+  // This is how wide the inboard scrollbars are, generally 0 except on Mac
+  const SCROLLBAR_WIDTH = (window.navigator.platform.match(/Mac/i)) ? 17 : 0;
+
 
   const { sendEvent } = shooter;
+  const log = global.log;
 
   function round10(n) {
     return Math.floor(n / 10) * 10;
   }
 
   function eventOptionsForBox(box) {
     return {
       cd1: round10(Math.abs(box.bottom - box.top)),
@@ -84,17 +88,17 @@ this.uicontrol = (function () {
 
   function eventOptionsForMove(posStart, posEnd) {
     return {
       cd1: round10(posEnd.y - posStart.y),
       cd2: round10(posEnd.x - posStart.x)
     };
   }
 
-  /***********************************************
+  /** *********************************************
    * State and stateHandlers infrastructure
    */
 
   // This enumerates all the anchors on the selection, and what part of the
   // selection they move:
   const movements = {
     topLeft: ["x1", "y1"],
     top: [null, "y1"],
@@ -170,17 +174,17 @@ this.uicontrol = (function () {
   let stateHandlers = {};
 
   function getState() {
     return getState.state;
   }
   getState.state = "cancel";
 
   function setState(s) {
-    if (! stateHandlers[s]) {
+    if (!stateHandlers[s]) {
       throw new Error("Unknown state: " + s);
     }
     let cur = getState.state;
     let handler = stateHandlers[cur];
     if (handler.end) {
       handler.end();
     }
     getState.state = s;
@@ -300,23 +304,23 @@ this.uicontrol = (function () {
         left: this.left,
         right: this.right,
         top: this.top,
         bottom: this.bottom
       };
     }
   }
 
-  Selection.getBoundingClientRect = function (el) {
-    if (! el.getBoundingClientRect) {
+  Selection.getBoundingClientRect = function(el) {
+    if (!el.getBoundingClientRect) {
       // Typically the <html> element or somesuch
       return null;
     }
     let rect = el.getBoundingClientRect();
-    if (! rect) {
+    if (!rect) {
       return null;
     }
     return new Selection(rect.left, rect.top, rect.right, rect.bottom);
   };
 
   /** Represents a single x/y point, typically for a mouse click that doesn't have a drag: */
   class Pos {
     constructor(x, y) {
@@ -331,104 +335,111 @@ this.uicontrol = (function () {
       );
     }
 
     distanceTo(x, y) {
       return Math.sqrt(Math.pow(this.x - x, 2), Math.pow(this.y - y));
     }
   }
 
-  /***********************************************
+  /** *********************************************
    * all stateHandlers
    */
 
   stateHandlers.onboarding = {
-    start: function () {
+    start() {
       if (typeof slides == "undefined") {
         throw new Error("Attempted to set state to onboarding without loading slides");
       }
       catcher.watchPromise(slides.display({
         onEnd: this.slidesOnEnd.bind(this)
       }));
     },
 
-    slidesOnEnd: function () {
+    slidesOnEnd() {
       callBackground("hasSeenOnboarding");
       setState("crosshairs");
     },
 
-    end: function () {
+    end() {
       slides.remove();
     }
   };
 
   stateHandlers.crosshairs = {
 
     cachedEl: null,
 
-    start: function () {
+    start() {
       selectedPos = mousedownPos = null;
       this.cachedEl = null;
       watchPromise(ui.iframe.display(installHandlersOnDocument, standardOverlayCallbacks).then(() => {
         ui.iframe.usePreSelection();
         ui.Box.remove();
         const handler = watchFunction(assertIsTrusted(keyupHandler));
-        document.addEventListener("keyup", handler, false);
+        document.addEventListener("keyup", handler);
         registeredDocumentHandlers.push({name: "keyup", doc: document, handler});
       }));
     },
 
-    mousemove: function (event) {
+    mousemove(event) {
       ui.PixelDimensions.display(event.pageX, event.pageY, event.pageX, event.pageY);
       if (event.target.classList &&
-          (! event.target.classList.contains("preview-overlay"))) {
+          (!event.target.classList.contains("preview-overlay"))) {
         // User is hovering over a toolbar button or control
         autoDetectRect = null;
         ui.HoverBox.hide();
         return;
       }
       let el;
-      if (event.target.classList.contains("preview-overlay")) {
+      if (event.target.classList && event.target.classList.contains("preview-overlay")) {
         // The hover is on the overlay, so we need to figure out the real element
         el = ui.iframe.getElementFromPoint(
           event.pageX + window.scrollX - window.pageXOffset,
           event.pageY + window.scrollY - window.pageYOffset
         );
+        let xpos = Math.floor(10 * (event.pageX - window.innerWidth / 2) / window.innerWidth);
+        let ypos = Math.floor(10 * (event.pageY - window.innerHeight / 2) / window.innerHeight)
+
+        for (var i = 0; i < 2; i++) {
+          let move = `translate(${xpos}px, ${ypos}px)`;
+          event.target.getElementsByClassName('eyeball')[i].style.transform = move;
+        }
       } else {
         // The hover is on the element we care about, so we use that
         el = event.target;
       }
       if (this.cachedEl && this.cachedEl === el) {
         // Still hovering over the same element
         return;
       }
       this.cachedEl = el;
       this.setAutodetectBasedOnElement(el);
     },
 
-    setAutodetectBasedOnElement: function (el) {
+    setAutodetectBasedOnElement(el) {
       let lastRect;
       let lastNode;
       let rect;
       let attemptExtend = false;
       let node = el;
       while (node) {
         rect = Selection.getBoundingClientRect(node);
-        if (! rect) {
+        if (!rect) {
           rect = lastRect;
           break;
         }
         if (rect.width > MAX_DETECT_WIDTH || rect.height > MAX_DETECT_HEIGHT) {
           // Then the last rectangle is better
           rect = lastRect;
           attemptExtend = true;
           break;
         }
         if (rect.width >= MIN_DETECT_WIDTH && rect.height >= MIN_DETECT_HEIGHT) {
-          if (! doNotAutoselectTags[node.tagName]) {
+          if (!doNotAutoselectTags[node.tagName]) {
             break;
           }
         }
         lastRect = rect;
         lastNode = node;
         node = node.parentNode;
       }
       if (rect && node) {
@@ -441,112 +452,121 @@ this.uicontrol = (function () {
       }
       if (rect && attemptExtend) {
         let extendNode = lastNode.nextSibling;
         while (extendNode) {
           if (extendNode.nodeType === document.ELEMENT_NODE) {
             break;
           }
           extendNode = extendNode.nextSibling;
-          if (! extendNode) {
+          if (!extendNode) {
             let parent = lastNode.parentNode;
-            for (let i=0; i<parent.childNodes.length; i++) {
+            for (let i = 0; i < parent.childNodes.length; i++) {
               if (parent.childNodes[i] === lastNode) {
-                extendNode = parent.childNodes[i+1];
+                extendNode = parent.childNodes[i + 1];
               }
             }
           }
         }
         if (extendNode) {
           let extendSelection = Selection.getBoundingClientRect(extendNode);
           let extendRect = rect.union(extendSelection);
           if (extendRect.width <= MAX_DETECT_WIDTH && extendRect.height <= MAX_DETECT_HEIGHT) {
             rect = extendRect;
           }
         }
       }
 
       if (rect && (rect.width < MIN_DETECT_ABSOLUTE_WIDTH || rect.height < MIN_DETECT_ABSOLUTE_HEIGHT)) {
         rect = null;
       }
-      if (! rect) {
+      if (!rect) {
         ui.HoverBox.hide();
       } else {
         ui.HoverBox.display(rect);
       }
       autoDetectRect = rect;
     },
 
     /** When we find an element, maybe there's one that's just a little bit better... */
-    evenBetterElement: function (node, origRect) {
+    evenBetterElement(node, origRect) {
       let el = node.parentNode;
       let ELEMENT_NODE = document.ELEMENT_NODE;
       while (el && el.nodeType == ELEMENT_NODE) {
-        if (! el.getAttribute) {
+        if (!el.getAttribute) {
           return null;
         }
         let role = el.getAttribute("role");
         if (role === "article" || (el.className && typeof el.className == "string" && el.className.search("tweet ") !== -1)) {
           let rect = Selection.getBoundingClientRect(el);
-          if (! rect) {
+          if (!rect) {
             return null;
           }
           if (rect.width <= MAX_DETECT_WIDTH && rect.height <= MAX_DETECT_HEIGHT) {
             return el;
-          } else {
-            return null;
           }
+          return null;
         }
         el = el.parentNode;
       }
       return null;
     },
 
-    mousedown: function (event) {
+    mousedown(event) {
       if (ui.isHeader(event.target)) {
-        return;
+        return undefined;
       }
+      // If the pageX is greater than this, then probably it's an attempt to get
+      // to the scrollbar, or an actual scroll, and not an attempt to start the
+      // selection:
+      let maxX = window.innerWidth - SCROLLBAR_WIDTH;
+      if (event.pageX >= maxX) {
+        event.stopPropagation();
+        event.preventDefault();
+        return false;
+      }
+
       mousedownPos = new Pos(event.pageX + window.scrollX, event.pageY + window.scrollY);
       setState("draggingReady");
       event.stopPropagation();
       event.preventDefault();
       return false;
     },
 
-    end: function () {
+    end() {
       ui.HoverBox.remove();
       ui.PixelDimensions.remove();
     }
   };
 
   stateHandlers.draggingReady = {
     minMove: 40, // px
     minAutoImageWidth: 40,
     minAutoImageHeight: 40,
     maxAutoElementWidth: 800,
     maxAutoElementHeight: 600,
 
-    start: function () {
+    start() {
       ui.iframe.usePreSelection();
       ui.Box.remove();
     },
 
-    mousemove: function (event) {
+    mousemove(event) {
       if (mousedownPos.distanceTo(event.pageX, event.pageY) > this.minMove) {
         selectedPos = new Selection(
           mousedownPos.x,
           mousedownPos.y,
           event.pageX + window.scrollX,
           event.pageY + window.scrollY);
         mousedownPos = null;
         setState("dragging");
       }
     },
 
-    mouseup: function (event) {
+    mouseup(event) {
       // If we don't get into "dragging" then we attempt an autoselect
       if (mouseupNoAutoselect) {
         sendEvent("cancel-selection", "selection-background-mousedown");
         setState("crosshairs");
         return false;
       }
       if (autoDetectRect) {
         selectedPos = autoDetectRect;
@@ -560,168 +580,167 @@ this.uicontrol = (function () {
         ui.Box.display(selectedPos, standardDisplayCallbacks);
         sendEvent("make-selection", "selection-click", eventOptionsForBox(selectedPos));
         setState("selected");
         sendEvent("autoselect");
       } else {
         sendEvent("no-selection", "no-element-found");
         setState("crosshairs");
       }
+      return undefined;
     },
 
-    click: function (event) {
+    click(event) {
       this.mouseup(event);
     },
 
-    findGoodEl: function () {
+    findGoodEl() {
       let el = mousedownPos.elementFromPoint();
-      if (! el) {
+      if (!el) {
         return null;
       }
       let isGoodEl = (el) => {
         if (el.nodeType != document.ELEMENT_NODE) {
           return false;
         }
         if (el.tagName == "IMG") {
           let rect = el.getBoundingClientRect();
           return rect.width >= this.minAutoImageWidth && rect.height >= this.minAutoImageHeight;
         }
         let display = window.getComputedStyle(el).display;
         if (['block', 'inline-block', 'table'].indexOf(display) != -1) {
           return true;
           // FIXME: not sure if this is useful:
-          //let rect = el.getBoundingClientRect();
-          //return rect.width <= this.maxAutoElementWidth && rect.height <= this.maxAutoElementHeight;
+          // let rect = el.getBoundingClientRect();
+          // return rect.width <= this.maxAutoElementWidth && rect.height <= this.maxAutoElementHeight;
         }
         return false;
       };
       while (el) {
         if (isGoodEl(el)) {
           return el;
         }
         el = el.parentNode;
       }
       return null;
     },
 
-    end: function () {
+    end() {
       mouseupNoAutoselect = false;
     }
 
   };
 
   stateHandlers.dragging = {
 
-    start: function () {
+    start() {
       ui.iframe.useSelection();
       ui.Box.display(selectedPos);
     },
 
-    mousemove: function (event) {
+    mousemove(event) {
       selectedPos.x2 = util.truncateX(event.pageX);
       selectedPos.y2 = util.truncateY(event.pageY);
       scrollIfByEdge(event.pageX, event.pageY);
       ui.Box.display(selectedPos);
       ui.PixelDimensions.display(event.pageX, event.pageY, selectedPos.width, selectedPos.height);
     },
 
-    mouseup: function (event) {
+    mouseup(event) {
       selectedPos.x2 = util.truncateX(event.pageX);
       selectedPos.y2 = util.truncateY(event.pageY);
       ui.Box.display(selectedPos, standardDisplayCallbacks);
       sendEvent(
         "make-selection", "selection-drag",
         eventOptionsForBox({
           top: selectedPos.y1,
           bottom: selectedPos.y2,
           left: selectedPos.x1,
           right: selectedPos.x2
         }));
       setState("selected");
     },
 
-    end: function () {
+    end() {
       ui.PixelDimensions.remove();
     }
   };
 
   stateHandlers.selected = {
-    start: function () {
+    start() {
       ui.iframe.useSelection();
     },
 
-    mousedown: function (event) {
+    mousedown(event) {
       let target = event.target;
       if (target.tagName == "HTML") {
         // This happens when you click on the scrollbar
-        return;
+        return undefined;
       }
       let direction = ui.Box.draggerDirection(target);
       if (direction) {
         sendEvent("start-resize-selection", "handle");
         stateHandlers.resizing.startResize(event, direction);
       } else if (ui.Box.isSelection(target)) {
         sendEvent("start-move-selection", "selection");
         stateHandlers.resizing.startResize(event, "move");
-      } else if (! ui.Box.isControl(target)) {
+      } else if (!ui.Box.isControl(target)) {
         mousedownPos = new Pos(event.pageX, event.pageY);
         setState("crosshairs");
       }
       event.preventDefault();
       return false;
     }
   };
 
   stateHandlers.resizing = {
-    start: function () {
+    start() {
       ui.iframe.useSelection();
       selectedPos.sortCoords();
     },
 
-    startResize: function (event, direction) {
+    startResize(event, direction) {
       selectedPos.sortCoords();
       resizeDirection = direction;
       resizeStartPos = new Pos(event.pageX, event.pageY);
       resizeStartSelected = selectedPos.clone();
       resizeHasMoved = false;
       setState("resizing");
     },
 
-    mousemove: function (event) {
+    mousemove(event) {
       this._resize(event);
       return false;
     },
 
-    mouseup: function (event) {
+    mouseup(event) {
       this._resize(event);
       sendEvent("selection-resized");
       ui.Box.display(selectedPos, standardDisplayCallbacks);
       if (resizeHasMoved) {
         if (resizeDirection == "move") {
           let startPos = new Pos(resizeStartSelected.left, resizeStartSelected.top);
           let endPos = new Pos(selectedPos.left, selectedPos.top);
           sendEvent(
             "move-selection", "mouseup",
             eventOptionsForMove(startPos, endPos));
         } else {
           sendEvent(
             "resize-selection", "mouseup",
             eventOptionsForResize(resizeStartSelected, selectedPos));
         }
+      } else if (resizeDirection == "move") {
+        sendEvent("keep-resize-selection", "mouseup");
       } else {
-        if (resizeDirection == "move") {
-          sendEvent("keep-resize-selection", "mouseup");
-        } else {
-          sendEvent("keep-move-selection", "mouseup");
-        }
+        sendEvent("keep-move-selection", "mouseup");
       }
       setState("selected");
     },
 
-    _resize: function (event) {
+    _resize(event) {
       let diffX = event.pageX - resizeStartPos.x;
       let diffY = event.pageY - resizeStartPos.y;
       let movement = movements[resizeDirection];
       if (movement[0]) {
         let moveX = movement[0];
         moveX = moveX == "*" ? ["x1", "x2"] : [moveX];
         for (let moveDir of moveX) {
           selectedPos[moveDir] =  util.truncateX(resizeStartSelected[moveDir] + diffX);
@@ -736,24 +755,24 @@ this.uicontrol = (function () {
       }
       if (diffX || diffY) {
         resizeHasMoved = true;
       }
       scrollIfByEdge(event.pageX, event.pageY);
       ui.Box.display(selectedPos);
     },
 
-    end: function () {
+    end() {
       resizeDirection = resizeStartPos = resizeStartSelected = null;
       selectedPos.sortCoords();
     }
   };
 
   stateHandlers.cancel = {
-    start: function () {
+    start() {
       ui.iframe.hide();
       ui.Box.remove();
     }
   };
 
   let documentWidth = Math.max(
     document.body.clientWidth,
     document.documentElement.clientWidth,
@@ -777,24 +796,24 @@ this.uicontrol = (function () {
     }
     if (pageX + SCROLL_BY_EDGE >= right && right < documentWidth) {
       window.scrollBy(SCROLL_BY_EDGE, 0);
     } else if (pageX - SCROLL_BY_EDGE <= left) {
       window.scrollBy(-SCROLL_BY_EDGE, 0);
     }
   }
 
-  /***********************************************
+  /** *********************************************
    * Selection communication
    */
 
    // If the slides module is loaded then we're supposed to onboard
   let shouldOnboard = typeof slides !== "undefined";
 
-  exports.activate = function () {
+  exports.activate = function() {
     if (isFrameset()) {
       callBackground("abortFrameset");
       selectorLoader.unloadModules();
       return;
     }
     addHandlers();
     // FIXME: self.options is gone
     if (self.options && self.options.styleMyShotsButton) {
@@ -806,56 +825,57 @@ this.uicontrol = (function () {
       setState("crosshairs");
     }
   }
 
   function isFrameset() {
     return document.body.tagName == "FRAMESET";
   }
 
-  exports.deactivate = function () {
+  exports.deactivate = function() {
     try {
       setState("cancel");
       callBackground('closeSelector');
       selectorLoader.unloadModules();
     } catch (e) {
       log.error('Error in deactivate', e)
       // Sometimes this fires so late that the document isn't available
       // We don't care about the exception, so we swallow it here
     }
   };
 
-  exports.unload = function () {
+  exports.unload = function() {
     // Note that ui.unload() will be called on its own
     removeHandlers();
   };
 
-  /***********************************************
+  /** *********************************************
    * Event handlers
    */
 
   let primedDocumentHandlers = new Map();
   let registeredDocumentHandlers = []
 
   function addHandlers() {
     ["mouseup", "mousedown", "mousemove", "click"].forEach((eventName) => {
-      let fn = watchFunction((function (eventName, event) {
+      let fn = watchFunction((function(eventName, event) {
         if (typeof event.button == "number" && event.button !== 0) {
           // Not a left click
-          return;
+          return undefined;
         }
         if (event.ctrlKey || event.shiftKey || event.altKey || event.metaKey) {
           // Modified click of key
-          return;
+          return undefined;
         }
         let state = getState();
         let handler = stateHandlers[state];
         if (handler[eventName]) {
           return handler[eventName](event);
         }
+        return undefined;
       }).bind(null, eventName));
       primedDocumentHandlers.set(eventName, fn);
     });
     primedDocumentHandlers.set("keyup", keyupHandler);
     window.addEventListener('beforeunload', beforeunloadHandler);
   }
 
   function installHandlersOnDocument(docObj) {
--- a/browser/extensions/screenshots/webextension/selector/util.js
+++ b/browser/extensions/screenshots/webextension/selector/util.js
@@ -1,49 +1,47 @@
 "use strict";
 
-this.util = (function () { // eslint-disable-line no-unused-vars
+this.util = (function() { // eslint-disable-line no-unused-vars
   let exports = {};
 
   /** Removes a node from its document, if it's a node and the node is attached to a parent */
-  exports.removeNode = function (el) {
+  exports.removeNode = function(el) {
     if (el && el.parentNode) {
-      el.parentNode.removeChild(el);
+      el.remove();
     }
   };
 
   /** Truncates the X coordinate to the document size */
-  exports.truncateX = function (x) {
+  exports.truncateX = function(x) {
     let max = Math.max(document.documentElement.clientWidth, document.body.clientWidth, document.documentElement.scrollWidth, document.body.scrollWidth);
     if (x < 0) {
       return 0;
     } else if (x > max) {
       return max;
-    } else {
-      return x;
     }
+    return x;
   };
 
   /** Truncates the Y coordinate to the document size */
-  exports.truncateY = function (y) {
+  exports.truncateY = function(y) {
     let max = Math.max(document.documentElement.clientHeight, document.body.clientHeight, document.documentElement.scrollHeight, document.body.scrollHeight);
     if (y < 0) {
       return 0;
     } else if (y > max) {
       return max;
-    } else {
-      return y;
     }
+    return y;
   };
 
   // Pixels of wiggle the captured region gets in captureSelectedText:
   var CAPTURE_WIGGLE = 10;
   const ELEMENT_NODE = document.ELEMENT_NODE;
 
-  exports.captureEnclosedText = function (box) {
+  exports.captureEnclosedText = function(box) {
     var scrollX = window.scrollX;
     var scrollY = window.scrollY;
     var text = [];
     function traverse(el) {
       var elBox = el.getBoundingClientRect();
       elBox = {
         top: elBox.top + scrollY,
         bottom: elBox.bottom + scrollY,
@@ -57,50 +55,49 @@ this.util = (function () { // eslint-dis
         // Totally outside of the box
         return;
       }
       if (elBox.bottom > box.bottom + CAPTURE_WIGGLE ||
           elBox.top < box.top - CAPTURE_WIGGLE ||
           elBox.right > box.right + CAPTURE_WIGGLE ||
           elBox.left < box.left - CAPTURE_WIGGLE) {
         // Partially outside the box
-        for (var i=0; i<el.childNodes.length; i++) {
+        for (var i = 0; i < el.childNodes.length; i++) {
           var child = el.childNodes[i];
           if (child.nodeType == ELEMENT_NODE) {
             traverse(child);
           }
         }
         return;
       }
       addText(el);
     }
     function addText(el) {
       let t;
       if (el.tagName == "IMG") {
         t = el.getAttribute("alt") || el.getAttribute("title");
       } else if (el.tagName == "A") {
         t = el.innerText;
-        if (el.getAttribute("href") && ! el.getAttribute("href").startsWith("#")) {
+        if (el.getAttribute("href") && !el.getAttribute("href").startsWith("#")) {
           t += " (" + el.href + ")";
         }
       } else {
         t = el.innerText;
       }
       if (t) {
         text.push(t);
       }
     }
     traverse(document.body);
     if (text.length) {
       let result = text.join("\n");
       result = result.replace(/^\s+/, "");
       result = result.replace(/\s+$/, "");
       result = result.replace(/[ \t]+\n/g, "\n");
       return result;
-    } else {
-      return null;
     }
+    return null;
   };
 
 
   return exports;
 })();
 null;
--- a/browser/extensions/screenshots/webextension/sitehelper.js
+++ b/browser/extensions/screenshots/webextension/sitehelper.js
@@ -1,15 +1,15 @@
 /* globals catcher, callBackground */
 /** This is a content script added to all screenshots.firefox.com pages, and allows the site to
     communicate with the add-on */
 
 "use strict";
 
-this.sitehelper = (function () {
+this.sitehelper = (function() {
 
   catcher.registerHandler((errorObj) => {
     callBackground("reportError", errorObj);
   });
 
 
   function sendCustomEvent(name, detail) {
     if (typeof detail == "object") {
@@ -26,18 +26,22 @@ this.sitehelper = (function () {
 
   document.addEventListener("request-login", catcher.watchFunction((event) => {
     let shotId = event.detail;
     catcher.watchPromise(callBackground("getAuthInfo", shotId || null).then((info) => {
       sendCustomEvent("login-successful", {deviceId: info.deviceId, isOwner: info.isOwner});
     }));
   }));
 
+  document.addEventListener("request-onboarding", catcher.watchFunction((event) => {
+    callBackground("requestOnboarding");
+  }));
+
   // Depending on the script loading order, the site might get the addon-present event,
   // but probably won't - instead the site will ask for that event after it has loaded
   document.addEventListener("request-addon-present", catcher.watchFunction(() => {
     sendCustomEvent("addon-present");
-  }), false);
+  }));
 
   sendCustomEvent("addon-present");
 
 })();
 null;