summaryrefslogtreecommitdiffstats
path: root/browser/extensions/pocket
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /browser/extensions/pocket
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'browser/extensions/pocket')
-rw-r--r--browser/extensions/pocket/bootstrap.js511
-rw-r--r--browser/extensions/pocket/content/AboutPocket.jsm93
-rw-r--r--browser/extensions/pocket/content/Pocket.jsm93
-rw-r--r--browser/extensions/pocket/content/main.js737
-rw-r--r--browser/extensions/pocket/content/panels/css/firasans.css6
-rw-r--r--browser/extensions/pocket/content/panels/css/normalize.css424
-rw-r--r--browser/extensions/pocket/content/panels/css/saved.css825
-rw-r--r--browser/extensions/pocket/content/panels/css/signup.css424
-rw-r--r--browser/extensions/pocket/content/panels/fonts/FiraSans-Regular.woffbin0 -> 179188 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/pocket.svg22
-rw-r--r--browser/extensions/pocket/content/panels/img/pocketerror@1x.pngbin0 -> 1479 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/pocketerror@2x.pngbin0 -> 3131 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/pocketlogo@1x.pngbin0 -> 3539 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/pocketlogo@2x.pngbin0 -> 7378 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/pocketlogosolo@1x.pngbin0 -> 1256 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/pocketlogosolo@2x.pngbin0 -> 2566 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/pocketmenuitem16.pngbin0 -> 264 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/pocketmenuitem16@2x.pngbin0 -> 641 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/pocketsignup_button@1x.pngbin0 -> 7315 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/pocketsignup_button@2x.pngbin0 -> 13480 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/pocketsignup_devices@1x.pngbin0 -> 22496 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/pocketsignup_devices@2x.pngbin0 -> 73925 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/pocketsignup_hero@1x.pngbin0 -> 44964 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/pocketsignup_hero@2x.pngbin0 -> 148877 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/signup_firefoxlogo@1x.pngbin0 -> 635 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/signup_firefoxlogo@2x.pngbin0 -> 1375 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/signup_help@1x.pngbin0 -> 659 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/signup_help@2x.pngbin0 -> 1420 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/signup_or@1x.pngbin0 -> 1843 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/signup_or@2x.pngbin0 -> 2925 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/tag_close@1x.pngbin0 -> 287 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/tag_close@2x.pngbin0 -> 508 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/tag_closeactive@1x.pngbin0 -> 208 bytes
-rw-r--r--browser/extensions/pocket/content/panels/img/tag_closeactive@2x.pngbin0 -> 354 bytes
-rw-r--r--browser/extensions/pocket/content/panels/js/messages.js78
-rw-r--r--browser/extensions/pocket/content/panels/js/saved.js608
-rw-r--r--browser/extensions/pocket/content/panels/js/signup.js193
-rw-r--r--browser/extensions/pocket/content/panels/js/tmpl.js242
-rw-r--r--browser/extensions/pocket/content/panels/js/vendor/handlebars.runtime.js660
-rw-r--r--browser/extensions/pocket/content/panels/js/vendor/jquery-2.1.1.min.js4
-rw-r--r--browser/extensions/pocket/content/panels/js/vendor/jquery.tokeninput.min.js954
-rw-r--r--browser/extensions/pocket/content/panels/license.txt35
-rw-r--r--browser/extensions/pocket/content/panels/saved.html19
-rw-r--r--browser/extensions/pocket/content/panels/signup.html18
-rw-r--r--browser/extensions/pocket/content/panels/tmpl/saved_premiumextras.handlebars2
-rw-r--r--browser/extensions/pocket/content/panels/tmpl/saved_premiumshell.handlebars6
-rw-r--r--browser/extensions/pocket/content/panels/tmpl/saved_shell.handlebars29
-rw-r--r--browser/extensions/pocket/content/panels/tmpl/signup_shell.handlebars32
-rw-r--r--browser/extensions/pocket/content/panels/tmpl/signupstoryboard_shell.handlebars43
-rw-r--r--browser/extensions/pocket/content/pktApi.jsm657
-rw-r--r--browser/extensions/pocket/content/pocket-content-process.js54
-rw-r--r--browser/extensions/pocket/install.rdf.in32
-rw-r--r--browser/extensions/pocket/jar.mn32
-rw-r--r--browser/extensions/pocket/locale/ast/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/az/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/bg/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/bn-BD/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/cs/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/da/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/de/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/dsb/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/en-GB/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/en-US/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/es-AR/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/es-CL/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/es-ES/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/es-MX/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/et/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/fi/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/fr/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/fy-NL/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/gu-IN/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/hr/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/hsb/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/hu/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/it/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/ja/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/jar.mn33
-rw-r--r--browser/extensions/pocket/locale/ka/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/kab/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/lt/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/lv/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/moz.build7
-rw-r--r--browser/extensions/pocket/locale/mr/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/ms/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/nl/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/nn-NO/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/or/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/pl/pocket.properties48
-rw-r--r--browser/extensions/pocket/locale/pt-BR/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/pt-PT/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/rm/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/ro/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/ru/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/sk/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/sl/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/sq/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/sr/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/sv-SE/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/te/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/th/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/tr/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/uk/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/zh-CN/pocket.properties43
-rw-r--r--browser/extensions/pocket/locale/zh-TW/pocket.properties43
-rw-r--r--browser/extensions/pocket/moz.build22
-rw-r--r--browser/extensions/pocket/skin/linux/Toolbar-inverted.pngbin0 -> 743 bytes
-rw-r--r--browser/extensions/pocket/skin/linux/Toolbar-inverted@2x.pngbin0 -> 2299 bytes
-rw-r--r--browser/extensions/pocket/skin/linux/Toolbar.pngbin0 -> 975 bytes
-rw-r--r--browser/extensions/pocket/skin/linux/Toolbar@2x.pngbin0 -> 3223 bytes
-rw-r--r--browser/extensions/pocket/skin/linux/menuPanel.pngbin0 -> 1377 bytes
-rw-r--r--browser/extensions/pocket/skin/linux/menuPanel@2x.pngbin0 -> 2671 bytes
-rw-r--r--browser/extensions/pocket/skin/linux/pocket.css10
-rw-r--r--browser/extensions/pocket/skin/osx/Toolbar-inverted.pngbin0 -> 1438 bytes
-rw-r--r--browser/extensions/pocket/skin/osx/Toolbar-inverted@2x.pngbin0 -> 3323 bytes
-rw-r--r--browser/extensions/pocket/skin/osx/Toolbar-yosemite.pngbin0 -> 958 bytes
-rw-r--r--browser/extensions/pocket/skin/osx/Toolbar-yosemite@2x.pngbin0 -> 2129 bytes
-rw-r--r--browser/extensions/pocket/skin/osx/Toolbar.pngbin0 -> 1571 bytes
-rw-r--r--browser/extensions/pocket/skin/osx/Toolbar@2x.pngbin0 -> 3613 bytes
-rw-r--r--browser/extensions/pocket/skin/osx/menuPanel-yosemite.pngbin0 -> 1570 bytes
-rw-r--r--browser/extensions/pocket/skin/osx/menuPanel-yosemite@2x.pngbin0 -> 3316 bytes
-rw-r--r--browser/extensions/pocket/skin/osx/menuPanel.pngbin0 -> 1976 bytes
-rw-r--r--browser/extensions/pocket/skin/osx/menuPanel@2x.pngbin0 -> 3861 bytes
-rw-r--r--browser/extensions/pocket/skin/osx/pocket.css42
-rw-r--r--browser/extensions/pocket/skin/shared/pocket.css79
-rw-r--r--browser/extensions/pocket/skin/windows/Toolbar-XP.pngbin0 -> 1141 bytes
-rw-r--r--browser/extensions/pocket/skin/windows/Toolbar-aero.pngbin0 -> 1163 bytes
-rw-r--r--browser/extensions/pocket/skin/windows/Toolbar-aero@2x.pngbin0 -> 2612 bytes
-rw-r--r--browser/extensions/pocket/skin/windows/Toolbar-inverted.pngbin0 -> 825 bytes
-rw-r--r--browser/extensions/pocket/skin/windows/Toolbar-inverted@2x.pngbin0 -> 1767 bytes
-rw-r--r--browser/extensions/pocket/skin/windows/Toolbar-lunaSilver.pngbin0 -> 1155 bytes
-rw-r--r--browser/extensions/pocket/skin/windows/Toolbar-win8.pngbin0 -> 649 bytes
-rw-r--r--browser/extensions/pocket/skin/windows/Toolbar-win8@2x.pngbin0 -> 1036 bytes
-rw-r--r--browser/extensions/pocket/skin/windows/Toolbar.pngbin0 -> 635 bytes
-rw-r--r--browser/extensions/pocket/skin/windows/Toolbar@2x.pngbin0 -> 1001 bytes
-rw-r--r--browser/extensions/pocket/skin/windows/menuPanel-aero.pngbin0 -> 2097 bytes
-rw-r--r--browser/extensions/pocket/skin/windows/menuPanel-aero@2x.pngbin0 -> 5063 bytes
-rw-r--r--browser/extensions/pocket/skin/windows/menuPanel.pngbin0 -> 1377 bytes
-rw-r--r--browser/extensions/pocket/skin/windows/menuPanel@2x.pngbin0 -> 2671 bytes
-rw-r--r--browser/extensions/pocket/skin/windows/pocket.css16
-rw-r--r--browser/extensions/pocket/test/.eslintrc.js7
-rw-r--r--browser/extensions/pocket/test/browser.ini6
-rw-r--r--browser/extensions/pocket/test/browser_pocket_ui_check.js61
-rw-r--r--browser/extensions/pocket/test/head.js67
-rw-r--r--browser/extensions/pocket/test/test.html11
145 files changed, 9349 insertions, 0 deletions
diff --git a/browser/extensions/pocket/bootstrap.js b/browser/extensions/pocket/bootstrap.js
new file mode 100644
index 000000000..c470eb8d3
--- /dev/null
+++ b/browser/extensions/pocket/bootstrap.js
@@ -0,0 +1,511 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+const {classes: Cc, interfaces: Ci, utils: Cu, manager: Cm} = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://services-common/utils.js");
+Cu.import("resource://gre/modules/Preferences.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Services",
+ "resource://gre/modules/Services.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
+ "resource:///modules/RecentWindow.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
+ "resource:///modules/CustomizableUI.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
+ "resource://gre/modules/AddonManager.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode",
+ "resource://gre/modules/ReaderMode.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "Pocket",
+ "chrome://pocket/content/Pocket.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "AboutPocket",
+ "chrome://pocket/content/AboutPocket.jsm");
+XPCOMUtils.defineLazyGetter(this, "gPocketBundle", function() {
+ return Services.strings.createBundle("chrome://pocket/locale/pocket.properties");
+});
+XPCOMUtils.defineLazyGetter(this, "gPocketStyleURI", function() {
+ return Services.io.newURI("chrome://pocket/skin/pocket.css", null, null);
+});
+
+// Due to bug 1051238 frame scripts are cached forever, so we can't update them
+// as a restartless add-on. The Math.random() is the work around for this.
+const PROCESS_SCRIPT = "chrome://pocket/content/pocket-content-process.js?" + Math.random();
+
+const PREF_BRANCH = "extensions.pocket.";
+const PREFS = {
+ enabled: true, // bug 1229937, figure out ui tour support
+ api: "api.getpocket.com",
+ site: "getpocket.com",
+ oAuthConsumerKey: "40249-e88c401e1b1f2242d9e441c4"
+};
+
+function setDefaultPrefs() {
+ let branch = Services.prefs.getDefaultBranch(PREF_BRANCH);
+ for (let [key, val] of Object.entries(PREFS)) {
+ // If someone beat us to setting a default, don't overwrite it. This can
+ // happen if distribution.ini sets the default first.
+ if (branch.getPrefType(key) != branch.PREF_INVALID)
+ continue;
+ switch (typeof val) {
+ case "boolean":
+ branch.setBoolPref(key, val);
+ break;
+ case "number":
+ branch.setIntPref(key, val);
+ break;
+ case "string":
+ branch.setCharPref(key, val);
+ break;
+ }
+ }
+}
+
+function createElementWithAttrs(document, type, attrs) {
+ let element = document.createElement(type);
+ Object.keys(attrs).forEach(function (attr) {
+ element.setAttribute(attr, attrs[attr]);
+ })
+ return element;
+}
+
+function CreatePocketWidget(reason) {
+ let id = "pocket-button"
+ let widget = CustomizableUI.getWidget(id);
+ // The widget is only null if we've created then destroyed the widget.
+ // Once we've actually called createWidget the provider will be set to
+ // PROVIDER_API.
+ if (widget && widget.provider == CustomizableUI.PROVIDER_API)
+ return;
+ // if upgrading from builtin version and the button was placed in ui,
+ // seenWidget will not be null
+ let seenWidget = CustomizableUI.getPlacementOfWidget("pocket-button", false, true);
+ let pocketButton = {
+ id: "pocket-button",
+ defaultArea: CustomizableUI.AREA_NAVBAR,
+ introducedInVersion: "pref",
+ type: "view",
+ tabSpecific: true,
+ viewId: "PanelUI-pocketView",
+ label: gPocketBundle.GetStringFromName("pocket-button.label"),
+ tooltiptext: gPocketBundle.GetStringFromName("pocket-button.tooltiptext"),
+ // Use forwarding functions here to avoid loading Pocket.jsm on startup:
+ onViewShowing: function() {
+ return Pocket.onPanelViewShowing.apply(this, arguments);
+ },
+ onViewHiding: function() {
+ return Pocket.onPanelViewHiding.apply(this, arguments);
+ },
+ onBeforeCreated: function(doc) {
+ // Bug 1223127,CUI should make this easier to do.
+ if (doc.getElementById("PanelUI-pocketView"))
+ return;
+ let view = doc.createElement("panelview");
+ view.id = "PanelUI-pocketView";
+ let panel = doc.createElement("vbox");
+ panel.setAttribute("class", "panel-subview-body");
+ view.appendChild(panel);
+ doc.getElementById("PanelUI-multiView").appendChild(view);
+ }
+ };
+
+ CustomizableUI.createWidget(pocketButton);
+ CustomizableUI.addListener(pocketButton);
+ // placed is null if location is palette
+ let placed = CustomizableUI.getPlacementOfWidget("pocket-button");
+
+ // a first time install will always have placed the button somewhere, and will
+ // not have a placement prior to creating the widget. Thus, !seenWidget &&
+ // placed.
+ if (reason == ADDON_ENABLE && !seenWidget && placed) {
+ // initially place the button after the bookmarks button if it is in the UI
+ let widgets = CustomizableUI.getWidgetIdsInArea(CustomizableUI.AREA_NAVBAR);
+ let bmbtn = widgets.indexOf("bookmarks-menu-button");
+ if (bmbtn > -1) {
+ CustomizableUI.moveWidgetWithinArea("pocket-button", bmbtn + 1);
+ }
+ }
+
+ // Uninstall the Pocket social provider if it exists, but only if we haven't
+ // already uninstalled it in this manner. That way the user can reinstall
+ // it if they prefer it without its being uninstalled every time they start
+ // the browser.
+ let SocialService;
+ try {
+ // For Firefox 51+
+ SocialService = Cu.import("resource:///modules/SocialService.jsm", {}).SocialService;
+ } catch (e) {
+ SocialService = Cu.import("resource://gre/modules/SocialService.jsm", {}).SocialService;
+ }
+
+ let origin = "https://getpocket.com";
+ SocialService.getProvider(origin, provider => {
+ if (provider) {
+ let pref = "social.backup.getpocket-com";
+ if (!Services.prefs.prefHasUserValue(pref)) {
+ let str = Cc["@mozilla.org/supports-string;1"].
+ createInstance(Ci.nsISupportsString);
+ str.data = JSON.stringify(provider.manifest);
+ Services.prefs.setComplexValue(pref, Ci.nsISupportsString, str);
+ SocialService.uninstallProvider(origin, () => {});
+ }
+ }
+ });
+
+}
+
+// PocketContextMenu
+// When the context menu is opened check if we need to build and enable pocket UI.
+var PocketContextMenu = {
+ init: function() {
+ Services.obs.addObserver(this, "on-build-contextmenu", false);
+ },
+ shutdown: function() {
+ Services.obs.removeObserver(this, "on-build-contextmenu");
+ // loop through windows and remove context menus
+ // iterate through all windows and add pocket to them
+ for (let win of CustomizableUI.windows) {
+ let document = win.document;
+ for (let id of ["context-pocket", "context-savelinktopocket"]) {
+ let element = document.getElementById(id);
+ if (element)
+ element.remove();
+ }
+ }
+ },
+ observe: function(aSubject, aTopic, aData) {
+ let subject = aSubject.wrappedJSObject;
+ let document = subject.menu.ownerDocument;
+ let pocketEnabled = CustomizableUI.getPlacementOfWidget("pocket-button");
+
+ let showSaveCurrentPageToPocket = !(subject.onTextInput || subject.onLink ||
+ subject.isContentSelected || subject.onImage ||
+ subject.onCanvas || subject.onVideo || subject.onAudio);
+ let targetUrl = subject.onLink ? subject.linkUrl : subject.pageUrl;
+ let targetURI = Services.io.newURI(targetUrl, null, null);
+ let canPocket = pocketEnabled && (targetURI.schemeIs("http") || targetURI.schemeIs("https") ||
+ (targetURI.schemeIs("about") && ReaderMode.getOriginalUrl(targetUrl)));
+
+ let showSaveLinkToPocket = canPocket && !showSaveCurrentPageToPocket && subject.onLink;
+
+ // create menu entries if necessary
+ let menu = document.getElementById("context-pocket");
+ if (!menu) {
+ menu = createElementWithAttrs(document, "menuitem", {
+ "id": "context-pocket",
+ "label": gPocketBundle.GetStringFromName("saveToPocketCmd.label"),
+ "accesskey": gPocketBundle.GetStringFromName("saveToPocketCmd.accesskey"),
+ "oncommand": "Pocket.savePage(gContextMenu.browser, gContextMenu.browser.currentURI.spec, gContextMenu.browser.contentTitle);"
+ });
+ let sibling = document.getElementById("context-savepage");
+ if (sibling.nextSibling) {
+ sibling.parentNode.insertBefore(menu, sibling.nextSibling);
+ } else {
+ sibling.parentNode.appendChild(menu);
+ }
+ }
+ menu.hidden = !(canPocket && showSaveCurrentPageToPocket);
+
+ menu = document.getElementById("context-savelinktopocket");
+ if (!menu) {
+ menu = createElementWithAttrs(document, "menuitem", {
+ "id": "context-savelinktopocket",
+ "label": gPocketBundle.GetStringFromName("saveLinkToPocketCmd.label"),
+ "accesskey": gPocketBundle.GetStringFromName("saveLinkToPocketCmd.accesskey"),
+ "oncommand": "Pocket.savePage(gContextMenu.browser, gContextMenu.linkURL);"
+ });
+ let sibling = document.getElementById("context-savelink");
+ if (sibling.nextSibling) {
+ sibling.parentNode.insertBefore(menu, sibling.nextSibling);
+ } else {
+ sibling.parentNode.appendChild(menu);
+ }
+ }
+ menu.hidden = !showSaveLinkToPocket;
+ }
+}
+
+// PocketReader
+// Listen for reader mode setup and add our button to the reader toolbar
+var PocketReader = {
+ _hidden: true,
+ get hidden() {
+ return this._hidden;
+ },
+ set hidden(hide) {
+ hide = !!hide;
+ if (hide === this._hidden)
+ return;
+ this._hidden = hide;
+ this.update();
+ },
+ startup: function() {
+ // Setup the listeners, update will be called when the widget is added,
+ // no need to do that now.
+ let mm = Services.mm;
+ mm.addMessageListener("Reader:OnSetup", this);
+ mm.addMessageListener("Reader:Clicked-pocket-button", this);
+ },
+ shutdown: function() {
+ let mm = Services.mm;
+ mm.removeMessageListener("Reader:OnSetup", this);
+ mm.removeMessageListener("Reader:Clicked-pocket-button", this);
+ this.hidden = true;
+ },
+ update: function() {
+ if (this.hidden) {
+ Services.mm.broadcastAsyncMessage("Reader:RemoveButton", { id: "pocket-button" });
+ } else {
+ Services.mm.broadcastAsyncMessage("Reader:AddButton",
+ { id: "pocket-button",
+ title: gPocketBundle.GetStringFromName("pocket-button.tooltiptext"),
+ image: "chrome://pocket/content/panels/img/pocket.svg#pocket-mark" });
+ }
+ },
+ receiveMessage: function(message) {
+ switch (message.name) {
+ case "Reader:OnSetup": {
+ // Tell the reader about our button.
+ if (this.hidden)
+ break;
+ message.target.messageManager.
+ sendAsyncMessage("Reader:AddButton", { id: "pocket-button",
+ title: gPocketBundle.GetStringFromName("pocket-button.tooltiptext"),
+ image: "chrome://pocket/content/panels/img/pocket.svg#pocket-mark"});
+ break;
+ }
+ case "Reader:Clicked-pocket-button": {
+ let doc = message.target.ownerDocument;
+ let pocketWidget = doc.getElementById("pocket-button");
+ let placement = CustomizableUI.getPlacementOfWidget("pocket-button");
+ if (placement) {
+ if (placement.area == CustomizableUI.AREA_PANEL) {
+ doc.defaultView.PanelUI.show().then(function() {
+ // The DOM node might not exist yet if the panel wasn't opened before.
+ pocketWidget = doc.getElementById("pocket-button");
+ pocketWidget.doCommand();
+ });
+ } else {
+ pocketWidget.doCommand();
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+
+function pktUIGetter(prop, window) {
+ return {
+ get: function() {
+ // delete any getters for properties loaded from main.js so we only load main.js once
+ delete window.pktUI;
+ delete window.pktApi;
+ delete window.pktUIMessaging;
+ Services.scriptloader.loadSubScript("chrome://pocket/content/main.js", window);
+ return window[prop];
+ },
+ configurable: true,
+ enumerable: true
+ };
+}
+
+var PocketOverlay = {
+ startup: function(reason) {
+ let styleSheetService = Cc["@mozilla.org/content/style-sheet-service;1"]
+ .getService(Ci.nsIStyleSheetService);
+ this._sheetType = styleSheetService.AUTHOR_SHEET;
+ this._cachedSheet = styleSheetService.preloadSheet(gPocketStyleURI,
+ this._sheetType);
+ Services.ppmm.loadProcessScript(PROCESS_SCRIPT, true);
+ PocketReader.startup();
+ CustomizableUI.addListener(this);
+ CreatePocketWidget(reason);
+ PocketContextMenu.init();
+
+ for (let win of CustomizableUI.windows) {
+ this.onWindowOpened(win);
+ }
+ },
+ shutdown: function(reason) {
+ let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
+ .getService(Ci.nsIMessageBroadcaster);
+ ppmm.broadcastAsyncMessage("PocketShuttingDown");
+ // Although the ppmm loads the scripts into the chrome process as well,
+ // we need to manually unregister here anyway to ensure these aren't part
+ // of the chrome process and avoid errors.
+ AboutPocket.aboutSaved.unregister();
+ AboutPocket.aboutSignup.unregister();
+
+ CustomizableUI.removeListener(this);
+ for (let window of CustomizableUI.windows) {
+ for (let id of ["panelMenu_pocket", "menu_pocket", "BMB_pocket",
+ "panelMenu_pocketSeparator", "menu_pocketSeparator",
+ "BMB_pocketSeparator"]) {
+ let element = window.document.getElementById(id);
+ if (element)
+ element.remove();
+ }
+ this.removeStyles(window);
+ // remove script getters/objects
+ delete window.Pocket;
+ delete window.pktApi;
+ delete window.pktUI;
+ delete window.pktUIMessaging;
+ }
+ CustomizableUI.destroyWidget("pocket-button");
+ PocketContextMenu.shutdown();
+ PocketReader.shutdown();
+ },
+ onWindowOpened: function(window) {
+ if (window.hasOwnProperty("pktUI"))
+ return;
+ this.setWindowScripts(window);
+ this.addStyles(window);
+ this.updateWindow(window);
+ },
+ setWindowScripts: function(window) {
+ XPCOMUtils.defineLazyModuleGetter(window, "Pocket",
+ "chrome://pocket/content/Pocket.jsm");
+ // Can't use XPCOMUtils for these because the scripts try to define the variables
+ // on window, and so the defineProperty inside defineLazyGetter fails.
+ Object.defineProperty(window, "pktApi", pktUIGetter("pktApi", window));
+ Object.defineProperty(window, "pktUI", pktUIGetter("pktUI", window));
+ Object.defineProperty(window, "pktUIMessaging", pktUIGetter("pktUIMessaging", window));
+ },
+ // called for each window as it is opened
+ updateWindow: function(window) {
+ // insert our three menu items
+ let document = window.document;
+ let hidden = !CustomizableUI.getPlacementOfWidget("pocket-button");
+
+ // add to bookmarksMenu
+ let sib = document.getElementById("menu_bookmarkThisPage");
+ if (sib && !document.getElementById("menu_pocket")) {
+ let menu = createElementWithAttrs(document, "menuitem", {
+ "id": "menu_pocket",
+ "label": gPocketBundle.GetStringFromName("pocketMenuitem.label"),
+ "class": "menuitem-iconic", // OSX only
+ "oncommand": "openUILink(Pocket.listURL, event);",
+ "hidden": hidden
+ });
+ let sep = createElementWithAttrs(document, "menuseparator", {
+ "id": "menu_pocketSeparator",
+ "hidden": hidden
+ });
+ sib.parentNode.insertBefore(menu, sib);
+ sib.parentNode.insertBefore(sep, sib);
+ }
+
+ // add to bookmarks-menu-button
+ sib = document.getElementById("BMB_bookmarksToolbar");
+ if (sib && !document.getElementById("BMB_pocket")) {
+ let menu = createElementWithAttrs(document, "menuitem", {
+ "id": "BMB_pocket",
+ "label": gPocketBundle.GetStringFromName("pocketMenuitem.label"),
+ "class": "menuitem-iconic bookmark-item subviewbutton",
+ "oncommand": "openUILink(Pocket.listURL, event);",
+ "hidden": hidden
+ });
+ let sep = createElementWithAttrs(document, "menuseparator", {
+ "id": "BMB_pocketSeparator",
+ "hidden": hidden
+ });
+ sib.parentNode.insertBefore(menu, sib);
+ sib.parentNode.insertBefore(sep, sib);
+ }
+
+ // add to PanelUI-bookmarks
+ sib = document.getElementById("panelMenuBookmarkThisPage");
+ if (sib && !document.getElementById("panelMenu_pocket")) {
+ let menu = createElementWithAttrs(document, "toolbarbutton", {
+ "id": "panelMenu_pocket",
+ "label": gPocketBundle.GetStringFromName("pocketMenuitem.label"),
+ "class": "subviewbutton cui-withicon",
+ "oncommand": "openUILink(Pocket.listURL, event);",
+ "hidden": hidden
+ });
+ let sep = createElementWithAttrs(document, "toolbarseparator", {
+ "id": "panelMenu_pocketSeparator",
+ "hidden": hidden
+ });
+ // nextSibling is no-id toolbarseparator
+ // insert separator first then button
+ sib = sib.nextSibling;
+ sib.parentNode.insertBefore(sep, sib);
+ sib.parentNode.insertBefore(menu, sib);
+ }
+ },
+ onWidgetAfterDOMChange: function(aWidgetNode) {
+ if (aWidgetNode.id != "pocket-button") {
+ return;
+ }
+ let doc = aWidgetNode.ownerDocument;
+ let hidden = !CustomizableUI.getPlacementOfWidget("pocket-button");
+ for (let prefix of ["panelMenu_", "menu_", "BMB_"]) {
+ let element = doc.getElementById(prefix + "pocket");
+ if (element) {
+ element.hidden = hidden;
+ doc.getElementById(prefix + "pocketSeparator").hidden = hidden;
+ }
+ }
+ // enable or disable reader button
+ PocketReader.hidden = hidden;
+ },
+
+ addStyles: function(win) {
+ let utils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+ utils.addSheet(this._cachedSheet, this._sheetType);
+ },
+
+ removeStyles: function(win) {
+ let utils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
+ utils.removeSheet(gPocketStyleURI, this._sheetType);
+ }
+
+}
+
+// use enabled pref as a way for tests (e.g. test_contextmenu.html) to disable
+// the addon when running.
+function prefObserver(aSubject, aTopic, aData) {
+ let enabled = Services.prefs.getBoolPref("extensions.pocket.enabled");
+ if (enabled)
+ PocketOverlay.startup(ADDON_ENABLE);
+ else
+ PocketOverlay.shutdown(ADDON_DISABLE);
+}
+
+function startup(data, reason) {
+ AddonManager.getAddonByID("isreaditlater@ideashower.com", addon => {
+ if (addon && addon.isActive)
+ return;
+ setDefaultPrefs();
+ // migrate enabled pref
+ if (Services.prefs.prefHasUserValue("browser.pocket.enabled")) {
+ Services.prefs.setBoolPref("extensions.pocket.enabled", Services.prefs.getBoolPref("browser.pocket.enabled"));
+ Services.prefs.clearUserPref("browser.pocket.enabled");
+ }
+ // watch pref change and enable/disable if necessary
+ Services.prefs.addObserver("extensions.pocket.enabled", prefObserver, false);
+ if (!Services.prefs.getBoolPref("extensions.pocket.enabled"))
+ return;
+ PocketOverlay.startup(reason);
+ });
+}
+
+function shutdown(data, reason) {
+ // For speed sake, we should only do a shutdown if we're being disabled.
+ // On an app shutdown, just let it fade away...
+ if (reason != APP_SHUTDOWN) {
+ Services.prefs.removeObserver("extensions.pocket.enabled", prefObserver);
+ PocketOverlay.shutdown(reason);
+ }
+}
+
+function install() {
+}
+
+function uninstall() {
+}
diff --git a/browser/extensions/pocket/content/AboutPocket.jsm b/browser/extensions/pocket/content/AboutPocket.jsm
new file mode 100644
index 000000000..c7f57aa87
--- /dev/null
+++ b/browser/extensions/pocket/content/AboutPocket.jsm
@@ -0,0 +1,93 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+const { interfaces: Ci, results: Cr, manager: Cm, utils: Cu } = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+// See LOG_LEVELS in Console.jsm. Common examples: "All", "Info", "Warn", & "Error".
+const PREF_LOG_LEVEL = "loop.debug.loglevel";
+
+XPCOMUtils.defineLazyGetter(this, "log", () => {
+ let ConsoleAPI = Cu.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;
+ let consoleOptions = {
+ maxLogLevelPref: PREF_LOG_LEVEL,
+ prefix: "Loop"
+ };
+ return new ConsoleAPI(consoleOptions);
+});
+
+
+function AboutPage(chromeURL, aboutHost, classID, description, uriFlags) {
+ this.chromeURL = chromeURL;
+ this.aboutHost = aboutHost;
+ this.classID = Components.ID(classID);
+ this.description = description;
+ this.uriFlags = uriFlags;
+}
+
+AboutPage.prototype = {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
+ getURIFlags: function(aURI) { // eslint-disable-line no-unused-vars
+ return this.uriFlags;
+ },
+
+ newChannel: function(aURI, aLoadInfo) {
+ let newURI = Services.io.newURI(this.chromeURL, null, null);
+ let channel = Services.io.newChannelFromURIWithLoadInfo(newURI,
+ aLoadInfo);
+ channel.originalURI = aURI;
+
+ if (this.uriFlags & Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT) {
+ let principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(aURI);
+ channel.owner = principal;
+ }
+ return channel;
+ },
+
+ createInstance: function(outer, iid) {
+ if (outer !== null) {
+ throw Cr.NS_ERROR_NO_AGGREGATION;
+ }
+ return this.QueryInterface(iid);
+ },
+
+ register: function() {
+ Cm.QueryInterface(Ci.nsIComponentRegistrar).registerFactory(
+ this.classID, this.description,
+ "@mozilla.org/network/protocol/about;1?what=" + this.aboutHost, this);
+ },
+
+ unregister: function() {
+ Cm.QueryInterface(Ci.nsIComponentRegistrar).unregisterFactory(
+ this.classID, this);
+ }
+};
+
+/* exported AboutPocket */
+var AboutPocket = {};
+
+XPCOMUtils.defineLazyGetter(AboutPocket, "aboutSaved", () =>
+ new AboutPage("chrome://pocket/content/panels/saved.html",
+ "pocket-saved",
+ "{3e759f54-37af-7843-9824-f71b5993ceed}",
+ "About Pocket Saved",
+ Ci.nsIAboutModule.ALLOW_SCRIPT |
+ Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT |
+ Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT)
+);
+
+XPCOMUtils.defineLazyGetter(AboutPocket, "aboutSignup", () =>
+ new AboutPage("chrome://pocket/content/panels/signup.html",
+ "pocket-signup",
+ "{8548329d-00c4-234e-8f17-75026db3b56e}",
+ "About Pocket Signup",
+ Ci.nsIAboutModule.ALLOW_SCRIPT |
+ Ci.nsIAboutModule.URI_SAFE_FOR_UNTRUSTED_CONTENT |
+ Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT)
+);
+
+this.EXPORTED_SYMBOLS = ["AboutPocket"];
diff --git a/browser/extensions/pocket/content/Pocket.jsm b/browser/extensions/pocket/content/Pocket.jsm
new file mode 100644
index 000000000..54f9cdf11
--- /dev/null
+++ b/browser/extensions/pocket/content/Pocket.jsm
@@ -0,0 +1,93 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+this.EXPORTED_SYMBOLS = ["Pocket"];
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
+ "resource:///modules/CustomizableUI.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode",
+ "resource://gre/modules/ReaderMode.jsm");
+
+var Pocket = {
+ get site() { return Services.prefs.getCharPref("extensions.pocket.site"); },
+ get listURL() { return "https://" + Pocket.site + "/?src=ff_ext"; },
+
+ /**
+ * Functions related to the Pocket panel UI.
+ */
+ onPanelViewShowing(event) {
+ let document = event.target.ownerDocument;
+ let window = document.defaultView;
+ let iframe = window.pktUI.getPanelFrame();
+
+ let urlToSave = Pocket._urlToSave;
+ let titleToSave = Pocket._titleToSave;
+ Pocket._urlToSave = null;
+ Pocket._titleToSave = null;
+ // ViewShowing fires immediately before it creates the contents,
+ // in lieu of an AfterViewShowing event, just spin the event loop.
+ window.setTimeout(function() {
+ if (urlToSave) {
+ window.pktUI.tryToSaveUrl(urlToSave, titleToSave);
+ } else {
+ window.pktUI.tryToSaveCurrentPage();
+ }
+
+ // pocketPanelDidHide in main.js set iframe to about:blank when it was
+ // hidden, make sure we're loading the save panel.
+ if (iframe.contentDocument &&
+ iframe.contentDocument.readyState == "complete" &&
+ iframe.contentDocument.documentURI != "about:blank") {
+ window.pktUI.pocketPanelDidShow();
+ } else {
+ // iframe didn't load yet. This seems to always be the case when in
+ // the toolbar panel, but never the case for a subview.
+ // XXX this only being fired when it's a _capturing_ listener!
+ iframe.addEventListener("load", Pocket.onFrameLoaded, true);
+ }
+ }, 0);
+ },
+
+ onFrameLoaded(event) {
+ let document = event.currentTarget.ownerDocument;
+ let window = document.defaultView;
+ let iframe = window.pktUI.getPanelFrame();
+
+ iframe.removeEventListener("load", Pocket.onFrameLoaded, true);
+ window.pktUI.pocketPanelDidShow();
+ },
+
+ onPanelViewHiding(event) {
+ let window = event.target.ownerGlobal;
+ window.pktUI.pocketPanelDidHide(event);
+ },
+
+ _urlToSave: null,
+ _titleToSave: null,
+ savePage(browser, url, title) {
+ let document = browser.ownerDocument;
+ let pocketWidget = document.getElementById("pocket-button");
+ let placement = CustomizableUI.getPlacementOfWidget("pocket-button");
+ if (!placement)
+ return;
+
+ this._urlToSave = url;
+ this._titleToSave = title;
+ if (placement.area == CustomizableUI.AREA_PANEL) {
+ let win = document.defaultView;
+ win.PanelUI.show().then(function() {
+ pocketWidget = document.getElementById("pocket-button");
+ pocketWidget.doCommand();
+ });
+ } else {
+ pocketWidget.doCommand();
+ }
+ },
+};
diff --git a/browser/extensions/pocket/content/main.js b/browser/extensions/pocket/content/main.js
new file mode 100644
index 000000000..3c1c5785e
--- /dev/null
+++ b/browser/extensions/pocket/content/main.js
@@ -0,0 +1,737 @@
+/*
+ * LICENSE
+ *
+ * POCKET MARKS
+ *
+ * Notwithstanding the permitted uses of the Software (as defined below) pursuant to the license set forth below, "Pocket," "Read It Later" and the Pocket icon and logos (collectively, the “Pocket Marks”) are registered and common law trademarks of Read It Later, Inc. This means that, while you have considerable freedom to redistribute and modify the Software, there are tight restrictions on your ability to use the Pocket Marks. This license does not grant you any rights to use the Pocket Marks except as they are embodied in the Software.
+ *
+ * ---
+ *
+ * SOFTWARE
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/*
+ * Pocket UI module
+ *
+ * Handles interactions with Pocket buttons, panels and menus.
+ *
+ */
+
+// TODO : Get the toolbar icons from Firefox's build (Nikki needs to give us a red saved icon)
+// TODO : [needs clarificaiton from Fx] Firefox's plan was to hide Pocket from context menus until the user logs in. Now that it's an extension I'm wondering if we still need to do this.
+// TODO : [needs clarificaiton from Fx] Reader mode (might be a something they need to do since it's in html, need to investigate their code)
+// TODO : [needs clarificaiton from Fx] Move prefs within pktApi.s to sqlite or a local file so it's not editable (and is safer)
+// TODO : [nice to have] - Immediately save, buffer the actions in a local queue and send (so it works offline, works like our native extensions)
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils",
+ "resource://gre/modules/PrivateBrowsingUtils.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ReaderMode",
+ "resource://gre/modules/ReaderMode.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "pktApi",
+ "chrome://pocket/content/pktApi.jsm");
+
+var pktUI = (function() {
+
+ // -- Initialization (on startup and new windows) -- //
+ var _currentPanelDidShow;
+ var _currentPanelDidHide;
+
+ // Init panel id at 0. The first actual panel id will have the number 1 so
+ // in case at some point any panel has the id 0 we know there is something
+ // wrong
+ var _panelId = 0;
+
+ var overflowMenuWidth = 230;
+ var overflowMenuHeight = 475;
+ var savePanelWidth = 350;
+ var savePanelHeights = {collapsed: 153, expanded: 272};
+
+ // -- Event Handling -- //
+
+ /**
+ * Event handler when Pocket toolbar button is pressed
+ */
+
+ function pocketPanelDidShow(event) {
+ if (_currentPanelDidShow) {
+ _currentPanelDidShow(event);
+ }
+
+ }
+
+ function pocketPanelDidHide(event) {
+ if (_currentPanelDidHide) {
+ _currentPanelDidHide(event);
+ }
+
+ // clear the panel
+ getPanelFrame().setAttribute('src', 'about:blank');
+ }
+
+
+ // -- Communication to API -- //
+
+ /**
+ * Either save or attempt to log the user in
+ */
+ function tryToSaveCurrentPage() {
+ tryToSaveUrl(getCurrentUrl(), getCurrentTitle());
+ }
+
+ function tryToSaveUrl(url, title) {
+
+ // If the user is logged in, go ahead and save the current page
+ if (pktApi.isUserLoggedIn()) {
+ saveAndShowConfirmation(url, title);
+ return;
+ }
+
+ // If the user is not logged in, show the logged-out state to prompt them to authenticate
+ showSignUp();
+ }
+
+
+ // -- Panel UI -- //
+
+ /**
+ * Show the sign-up panel
+ */
+ function showSignUp() {
+ // AB test: Direct logged-out users to tab vs panel
+ if (pktApi.getSignupPanelTabTestVariant() == 'v2')
+ {
+ let site = Services.prefs.getCharPref("extensions.pocket.site");
+ openTabWithUrl('https://' + site + '/firefox_learnmore?s=ffi&t=autoredirect&tv=page_learnmore&src=ff_ext', true);
+
+ // force the panel closed before it opens
+ getPanel().hidePopup();
+
+ return;
+ }
+
+ // Control: Show panel as normal
+ getFirefoxAccountSignedInUser(function(userdata)
+ {
+ var fxasignedin = (typeof userdata == 'object' && userdata !== null) ? '1' : '0';
+ var startheight = 490;
+ var inOverflowMenu = isInOverflowMenu();
+ var controlvariant = pktApi.getSignupPanelTabTestVariant() == 'control';
+
+ if (inOverflowMenu)
+ {
+ startheight = overflowMenuHeight;
+ }
+ else
+ {
+ startheight = 460;
+ if (fxasignedin == '1')
+ {
+ startheight = 406;
+ }
+ }
+ if (!controlvariant) {
+ startheight = 427;
+ }
+ var variant;
+ if (inOverflowMenu)
+ {
+ variant = 'overflow';
+ }
+ else
+ {
+ variant = 'storyboard_lm';
+ }
+
+ showPanel("about:pocket-signup?pockethost="
+ + Services.prefs.getCharPref("extensions.pocket.site")
+ + "&fxasignedin="
+ + fxasignedin
+ + "&variant="
+ + variant
+ + '&controlvariant='
+ + controlvariant
+ + '&inoverflowmenu='
+ + inOverflowMenu
+ + "&locale="
+ + getUILocale(), {
+ onShow: function() {
+ },
+ onHide: panelDidHide,
+ width: inOverflowMenu ? overflowMenuWidth : 300,
+ height: startheight
+ });
+ });
+ }
+
+ /**
+ * Show the logged-out state / sign-up panel
+ */
+ function saveAndShowConfirmation(url, title) {
+
+ // Validate input parameter
+ if (typeof url !== 'undefined' && url.startsWith("about:reader?url=")) {
+ url = ReaderMode.getOriginalUrl(url);
+ }
+
+ var isValidURL = (typeof url !== 'undefined' && (url.startsWith("http") || url.startsWith('https')));
+
+ var inOverflowMenu = isInOverflowMenu();
+ var startheight = pktApi.isPremiumUser() && isValidURL ? savePanelHeights.expanded : savePanelHeights.collapsed;
+ if (inOverflowMenu) {
+ startheight = overflowMenuHeight;
+ }
+
+ var panelId = showPanel("about:pocket-saved?pockethost=" + Services.prefs.getCharPref("extensions.pocket.site") + "&premiumStatus=" + (pktApi.isPremiumUser() ? '1' : '0') + '&inoverflowmenu='+inOverflowMenu + "&locale=" + getUILocale(), {
+ onShow: function() {
+ var saveLinkMessageId = 'saveLink';
+
+ // Send error message for invalid url
+ if (!isValidURL) {
+ // TODO: Pass key for localized error in error object
+ let error = {
+ message: 'Only links can be saved',
+ localizedKey: "onlylinkssaved"
+ };
+ pktUIMessaging.sendErrorMessageToPanel(panelId, saveLinkMessageId, error);
+ return;
+ }
+
+ // Check online state
+ if (!navigator.onLine) {
+ // TODO: Pass key for localized error in error object
+ let error = {
+ message: 'You must be connected to the Internet in order to save to Pocket. Please connect to the Internet and try again.'
+ };
+ pktUIMessaging.sendErrorMessageToPanel(panelId, saveLinkMessageId, error);
+ return;
+ }
+
+ // Add url
+ var options = {
+ success: function(data, request) {
+ var item = data.item;
+ var successResponse = {
+ status: "success",
+ item: item
+ };
+ pktUIMessaging.sendMessageToPanel(panelId, saveLinkMessageId, successResponse);
+ },
+ error: function(error, request) {
+ // If user is not authorized show singup page
+ if (request.status === 401) {
+ showSignUp();
+ return;
+ }
+
+ // If there is no error message in the error use a
+ // complete catch-all
+ var errorMessage = error.message || "There was an error when trying to save to Pocket.";
+ var panelError = { message: errorMessage}
+
+ // Send error message to panel
+ pktUIMessaging.sendErrorMessageToPanel(panelId, saveLinkMessageId, panelError);
+ }
+ }
+
+ // Add title if given
+ if (typeof title !== "undefined") {
+ options.title = title;
+ }
+
+ // Send the link
+ pktApi.addLink(url, options);
+ },
+ onHide: panelDidHide,
+ width: inOverflowMenu ? overflowMenuWidth : savePanelWidth,
+ height: startheight
+ });
+ }
+
+ /**
+ * Open a generic panel
+ */
+ function showPanel(url, options) {
+
+ // Add new panel id
+ _panelId += 1;
+ url += ("&panelId=" + _panelId);
+
+ // We don't have to hide and show the panel again if it's already shown
+ // as if the user tries to click again on the toolbar button the overlay
+ // will close instead of the button will be clicked
+ var iframe = getPanelFrame();
+
+ // Register event handlers
+ registerEventMessages();
+
+ // Load the iframe
+ iframe.setAttribute('src', url);
+
+ // Uncomment to leave panel open -- for debugging
+ // panel.setAttribute('noautohide', true);
+ // panel.setAttribute('consumeoutsideclicks', false);
+ //
+
+ // For some reason setting onpopupshown and onpopuphidden on the panel directly didn't work, so
+ // do it this hacky way for now
+ _currentPanelDidShow = options.onShow;
+ _currentPanelDidHide = options.onHide;
+
+ resizePanel({
+ width: options.width,
+ height: options.height
+ });
+ return _panelId;
+ }
+
+ /**
+ * Resize the panel
+ * options = {
+ * width: ,
+ * height: ,
+ * animate [default false]
+ * }
+ */
+ function resizePanel(options) {
+ var iframe = getPanelFrame();
+ var subview = getSubview();
+
+ if (subview) {
+ // Use the subview's size
+ iframe.style.width = "100%";
+ iframe.style.height = subview.parentNode.clientHeight + "px";
+ } else {
+ // Set an explicit size, panel will adapt.
+ iframe.style.width = options.width + "px";
+ iframe.style.height = options.height + "px";
+ }
+ }
+
+ /**
+ * Called when the signup and saved panel was hidden
+ */
+ function panelDidHide() {
+ // clear the onShow and onHide values
+ _currentPanelDidShow = null;
+ _currentPanelDidHide = null;
+ }
+
+ /**
+ * Register all of the messages needed for the panels
+ */
+ function registerEventMessages() {
+ var iframe = getPanelFrame();
+
+ // Only register the messages once
+ var didInitAttributeKey = 'did_init';
+ var didInitMessageListener = iframe.getAttribute(didInitAttributeKey);
+ if (typeof didInitMessageListener !== "undefined" && didInitMessageListener == 1) {
+ return;
+ }
+ iframe.setAttribute(didInitAttributeKey, 1);
+
+ // When the panel is displayed it generated an event called
+ // "show": we will listen for that event and when it happens,
+ // send our own "show" event to the panel's script, so the
+ // script can prepare the panel for display.
+ var _showMessageId = "show";
+ pktUIMessaging.addMessageListener(iframe, _showMessageId, function(panelId, data) {
+ // Let panel know that it is ready
+ pktUIMessaging.sendMessageToPanel(panelId, _showMessageId);
+ });
+
+ // Open a new tab with a given url and activate if
+ var _openTabWithUrlMessageId = "openTabWithUrl";
+ pktUIMessaging.addMessageListener(iframe, _openTabWithUrlMessageId, function(panelId, data, contentPrincipal) {
+ try {
+ urlSecurityCheck(data.url, contentPrincipal, Services.scriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL);
+ } catch (ex) {
+ return;
+ }
+
+ // Check if the tab should become active after opening
+ var activate = true;
+ if (typeof data.activate !== "undefined") {
+ activate = data.activate;
+ }
+
+ var url = data.url;
+ openTabWithUrl(url, activate);
+ pktUIMessaging.sendResponseMessageToPanel(panelId, _openTabWithUrlMessageId, url);
+ });
+
+ // Close the panel
+ var _closeMessageId = "close";
+ pktUIMessaging.addMessageListener(iframe, _closeMessageId, function(panelId, data) {
+ getPanel().hidePopup();
+ });
+
+ // Send the current url to the panel
+ var _getCurrentURLMessageId = "getCurrentURL";
+ pktUIMessaging.addMessageListener(iframe, _getCurrentURLMessageId, function(panelId, data) {
+ pktUIMessaging.sendResponseMessageToPanel(panelId, _getCurrentURLMessageId, getCurrentUrl());
+ });
+
+ var _resizePanelMessageId = "resizePanel";
+ pktUIMessaging.addMessageListener(iframe, _resizePanelMessageId, function(panelId, data) {
+ resizePanel(data);
+ });
+
+ // Callback post initialization to tell background script that panel is "ready" for communication.
+ pktUIMessaging.addMessageListener(iframe, "listenerReady", function(panelId, data) {
+
+ });
+
+ pktUIMessaging.addMessageListener(iframe, "collapseSavePanel", function(panelId, data) {
+ if (!pktApi.isPremiumUser() && !isInOverflowMenu())
+ resizePanel({width:savePanelWidth, height:savePanelHeights.collapsed});
+ });
+
+ pktUIMessaging.addMessageListener(iframe, "expandSavePanel", function(panelId, data) {
+ if (!isInOverflowMenu())
+ resizePanel({width:savePanelWidth, height:savePanelHeights.expanded});
+ });
+
+ // Ask for recently accessed/used tags for auto complete
+ var _getTagsMessageId = "getTags";
+ pktUIMessaging.addMessageListener(iframe, _getTagsMessageId, function(panelId, data) {
+ pktApi.getTags(function(tags, usedTags) {
+ pktUIMessaging.sendResponseMessageToPanel(panelId, _getTagsMessageId, {
+ tags: tags,
+ usedTags: usedTags
+ });
+ });
+ });
+
+ // Ask for suggested tags based on passed url
+ var _getSuggestedTagsMessageId = "getSuggestedTags";
+ pktUIMessaging.addMessageListener(iframe, _getSuggestedTagsMessageId, function(panelId, data) {
+ pktApi.getSuggestedTagsForURL(data.url, {
+ success: function(data, response) {
+ var suggestedTags = data.suggested_tags;
+ var successResponse = {
+ status: "success",
+ value: {
+ suggestedTags: suggestedTags
+ }
+ }
+ pktUIMessaging.sendResponseMessageToPanel(panelId, _getSuggestedTagsMessageId, successResponse);
+ },
+ error: function(error, response) {
+ pktUIMessaging.sendErrorResponseMessageToPanel(panelId, _getSuggestedTagsMessageId, error);
+ }
+ })
+ });
+
+ // Pass url and array list of tags, add to existing save item accordingly
+ var _addTagsMessageId = "addTags";
+ pktUIMessaging.addMessageListener(iframe, _addTagsMessageId, function(panelId, data) {
+ pktApi.addTagsToURL(data.url, data.tags, {
+ success: function(data, response) {
+ var successResponse = {status: "success"};
+ pktUIMessaging.sendResponseMessageToPanel(panelId, _addTagsMessageId, successResponse);
+ },
+ error: function(error, response) {
+ pktUIMessaging.sendErrorResponseMessageToPanel(panelId, _addTagsMessageId, error);
+ }
+ });
+ });
+
+ // Based on clicking "remove page" CTA, and passed unique item id, remove the item
+ var _deleteItemMessageId = "deleteItem";
+ pktUIMessaging.addMessageListener(iframe, _deleteItemMessageId, function(panelId, data) {
+ pktApi.deleteItem(data.itemId, {
+ success: function(data, response) {
+ var successResponse = {status: "success"};
+ pktUIMessaging.sendResponseMessageToPanel(panelId, _deleteItemMessageId, successResponse);
+ },
+ error: function(error, response) {
+ pktUIMessaging.sendErrorResponseMessageToPanel(panelId, _deleteItemMessageId, error);
+ }
+ })
+ });
+
+ var _initL10NMessageId = "initL10N";
+ pktUIMessaging.addMessageListener(iframe, _initL10NMessageId, function(panelId, data) {
+ var strings = {};
+ var bundle = Services.strings.createBundle("chrome://pocket/locale/pocket.properties");
+ var e = bundle.getSimpleEnumeration();
+ while (e.hasMoreElements()) {
+ var str = e.getNext().QueryInterface(Components.interfaces.nsIPropertyElement);
+ if (str.key in data) {
+ strings[str.key] = bundle.formatStringFromName(str.key, data[str.key], data[str.key].length);
+ } else {
+ strings[str.key] = str.value;
+ }
+ }
+ pktUIMessaging.sendResponseMessageToPanel(panelId, _initL10NMessageId, { strings: strings });
+ });
+
+ }
+
+ // -- Browser Navigation -- //
+
+ /**
+ * Open a new tab with a given url and notify the iframe panel that it was opened
+ */
+
+ function openTabWithUrl(url) {
+ let recentWindow = Services.wm.getMostRecentWindow("navigator:browser");
+ if (!recentWindow) {
+ Cu.reportError("Pocket: No open browser windows to openTabWithUrl");
+ return;
+ }
+
+ // If the user is in permanent private browsing than this is not an issue,
+ // since the current window will always share the same cookie jar as the other
+ // windows.
+ if (!PrivateBrowsingUtils.isWindowPrivate(recentWindow) ||
+ PrivateBrowsingUtils.permanentPrivateBrowsing) {
+ recentWindow.openUILinkIn(url, "tab");
+ return;
+ }
+
+ let windows = Services.wm.getEnumerator("navigator:browser");
+ while (windows.hasMoreElements()) {
+ let win = windows.getNext();
+ if (!PrivateBrowsingUtils.isWindowPrivate(win)) {
+ win.openUILinkIn(url, "tab");
+ return;
+ }
+ }
+
+ // If there were no non-private windows opened already.
+ recentWindow.openUILinkIn(url, "window");
+ }
+
+
+ // -- Helper Functions -- //
+
+ function getCurrentUrl() {
+ return getBrowser().currentURI.spec;
+ }
+
+ function getCurrentTitle() {
+ return getBrowser().contentTitle;
+ }
+
+ function getPanel() {
+ var frame = getPanelFrame();
+ var panel = frame;
+ while (panel && panel.localName != "panel") {
+ panel = panel.parentNode;
+ }
+ return panel;
+ }
+
+ function getPanelFrame() {
+ var frame = document.getElementById('pocket-panel-iframe');
+ if (!frame) {
+ var frameParent = document.getElementById("PanelUI-pocketView").firstChild;
+ frame = document.createElement("iframe");
+ frame.id = 'pocket-panel-iframe';
+ frame.setAttribute("type", "content");
+ frameParent.appendChild(frame);
+ }
+ return frame;
+ }
+
+ function getSubview() {
+ var view = document.getElementById("PanelUI-pocketView");
+ if (view && view.getAttribute("current") == "true")
+ return view;
+ return null;
+ }
+
+ function isInOverflowMenu() {
+ var subview = getSubview();
+ return !!subview;
+ }
+
+ function getFirefoxAccountSignedInUser(callback) {
+ fxAccounts.getSignedInUser().then(userData => {
+ callback(userData);
+ }).then(null, error => {
+ callback();
+ });
+ }
+
+ function getUILocale() {
+ var locale = Cc["@mozilla.org/chrome/chrome-registry;1"].
+ getService(Ci.nsIXULChromeRegistry).
+ getSelectedLocale("browser");
+ return locale;
+ }
+
+ /**
+ * Public functions
+ */
+ return {
+ getPanelFrame: getPanelFrame,
+
+ openTabWithUrl: openTabWithUrl,
+
+ pocketPanelDidShow: pocketPanelDidShow,
+ pocketPanelDidHide: pocketPanelDidHide,
+
+ tryToSaveUrl: tryToSaveUrl,
+ tryToSaveCurrentPage: tryToSaveCurrentPage
+ };
+}());
+
+// -- Communication to Background -- //
+// https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Interaction_between_privileged_and_non-privileged_pages
+var pktUIMessaging = (function() {
+
+ /**
+ * Prefix message id for message listening
+ */
+ function prefixedMessageId(messageId) {
+ return 'PKT_' + messageId;
+ }
+
+ /**
+ * Register a listener and callback for a specific messageId
+ */
+ function addMessageListener(iframe, messageId, callback) {
+ iframe.addEventListener(prefixedMessageId(messageId), function(e) {
+ var nodePrincipal = e.target.nodePrincipal;
+ // ignore to ensure we do not pick up other events in the browser
+ if (!nodePrincipal || !nodePrincipal.URI || !nodePrincipal.URI.spec.startsWith("about:pocket")) {
+ return;
+ }
+
+ // Pass in information to callback
+ var payload = JSON.parse(e.target.getAttribute("payload"))[0];
+ var panelId = payload.panelId;
+ var data = payload.data;
+ callback(panelId, data, nodePrincipal);
+
+ // Cleanup the element
+ e.target.parentNode.removeChild(e.target);
+
+ }, false, true);
+ }
+
+ /**
+ * Send a message to the panel's iframe
+ */
+ function sendMessageToPanel(panelId, messageId, payload) {
+
+ if (!isPanelIdValid(panelId)) { return; }
+
+ var panelFrame = pktUI.getPanelFrame();
+ if (!isPocketPanelFrameValid(panelFrame)) { return; }
+
+ var doc = panelFrame.contentWindow.document;
+ var documentElement = doc.documentElement;
+
+ // Send message to panel
+ var panelMessageId = prefixedMessageId(panelId + '_' + messageId);
+
+ var AnswerEvt = doc.createElement("PKTMessage");
+ AnswerEvt.setAttribute("payload", JSON.stringify([payload]));
+ documentElement.appendChild(AnswerEvt);
+
+ var event = doc.createEvent("HTMLEvents");
+ event.initEvent(panelMessageId, true, false);
+ AnswerEvt.dispatchEvent(event);
+ }
+
+ function sendResponseMessageToPanel(panelId, messageId, payload) {
+ var responseMessageId = messageId + "Response";
+ sendMessageToPanel(panelId, responseMessageId, payload);
+ }
+
+ /**
+ * Helper function to package an error object and send it to the panel
+ * iframe as a message response
+ */
+ function sendErrorMessageToPanel(panelId, messageId, error) {
+ var errorResponse = {status: "error", error: error};
+ sendMessageToPanel(panelId, messageId, errorResponse);
+ }
+
+ function sendErrorResponseMessageToPanel(panelId, messageId, error) {
+ var errorResponse = {status: "error", error: error};
+ sendResponseMessageToPanel(panelId, messageId, errorResponse);
+ }
+
+ /**
+ * Validation
+ */
+
+ function isPanelIdValid(panelId) {
+ // First check if panelId has a valid value > 0. We set the panelId to
+ // 0 to start. But if for some reason the message is attempted to be
+ // sent before the panel has a panelId, then it's going to send out
+ // a message with panelId 0, which is never going to be heard. If this
+ // happens, it means some race condition occurred where the panel was
+ // trying to communicate before it should.
+ if (panelId === 0) {
+ console.warn("Tried to send message to panel with id 0.")
+ return false;
+ }
+
+ return true
+ }
+
+ function isPocketPanelFrameValid(panelFrame) {
+ // Check if panel is available if not throw a warning and bailout.
+ // We likely try to send to a panel that is not visible anymore
+ if (typeof panelFrame === "undefined") {
+ console.warn("Pocket panel frame is undefined");
+ return false;
+ }
+
+ var contentWindow = panelFrame.contentWindow;
+ if (typeof contentWindow == "undefined") {
+ console.warn("Pocket panel frame content window is undefined");
+ return false;
+ }
+
+ var doc = contentWindow.document;
+ if (typeof doc === "undefined") {
+ console.warn("Pocket panel frame content window document is undefined");
+ return false;
+ }
+
+ var documentElement = doc.documentElement;
+ if (typeof documentElement === "undefined") {
+ console.warn("Pocket panel frame content window document document element is undefined");
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Public
+ */
+ return {
+ addMessageListener: addMessageListener,
+ sendMessageToPanel: sendMessageToPanel,
+ sendResponseMessageToPanel: sendResponseMessageToPanel,
+ sendErrorMessageToPanel: sendErrorMessageToPanel,
+ sendErrorResponseMessageToPanel: sendErrorResponseMessageToPanel
+ }
+}());
diff --git a/browser/extensions/pocket/content/panels/css/firasans.css b/browser/extensions/pocket/content/panels/css/firasans.css
new file mode 100644
index 000000000..5915345d6
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/css/firasans.css
@@ -0,0 +1,6 @@
+@font-face {
+ font-family: 'FiraSans';
+ src: url('../fonts/FiraSans-Regular.woff') format('woff');
+ font-weight: normal;
+ font-style: normal;
+} \ No newline at end of file
diff --git a/browser/extensions/pocket/content/panels/css/normalize.css b/browser/extensions/pocket/content/panels/css/normalize.css
new file mode 100644
index 000000000..b7b4b746e
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/css/normalize.css
@@ -0,0 +1,424 @@
+/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
+
+/**
+ * 1. Set default font family to sans-serif.
+ * 2. Prevent iOS text size adjust after orientation change, without disabling
+ * user zoom.
+ */
+
+html {
+ font-family: sans-serif; /* 1 */
+}
+
+/**
+ * Remove default margin.
+ */
+
+body {
+ margin: 0;
+}
+
+/* HTML5 display definitions
+ ========================================================================== */
+
+/**
+ * Correct `block` display not defined for any HTML5 element in IE 8/9.
+ * Correct `block` display not defined for `details` or `summary` in IE 10/11
+ * and Firefox.
+ * Correct `block` display not defined for `main` in IE 11.
+ */
+
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+main,
+menu,
+nav,
+section,
+summary {
+ display: block;
+}
+
+/**
+ * 1. Correct `inline-block` display not defined in IE 8/9.
+ * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
+ */
+
+audio,
+canvas,
+progress,
+video {
+ display: inline-block; /* 1 */
+ vertical-align: baseline; /* 2 */
+}
+
+/**
+ * Prevent modern browsers from displaying `audio` without controls.
+ * Remove excess height in iOS 5 devices.
+ */
+
+audio:not([controls]) {
+ display: none;
+ height: 0;
+}
+
+/**
+ * Address `[hidden]` styling not present in IE 8/9/10.
+ * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
+ */
+
+[hidden],
+template {
+ display: none;
+}
+
+/* Links
+ ========================================================================== */
+
+/**
+ * Remove the gray background color from active links in IE 10.
+ */
+
+a {
+ background-color: transparent;
+}
+
+/**
+ * Improve readability when focused and also mouse hovered in all browsers.
+ */
+
+a:active,
+a:hover {
+ outline: 0;
+}
+
+/* Text-level semantics
+ ========================================================================== */
+
+/**
+ * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
+ */
+
+abbr[title] {
+ border-bottom: 1px dotted;
+}
+
+/**
+ * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
+ */
+
+b,
+strong {
+ font-weight: bold;
+}
+
+/**
+ * Address styling not present in Safari and Chrome.
+ */
+
+dfn {
+ font-style: italic;
+}
+
+/**
+ * Address variable `h1` font-size and margin within `section` and `article`
+ * contexts in Firefox 4+, Safari, and Chrome.
+ */
+
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+
+/**
+ * Address styling not present in IE 8/9.
+ */
+
+mark {
+ background: #ff0;
+ color: #000;
+}
+
+/**
+ * Address inconsistent and variable font size in all browsers.
+ */
+
+small {
+ font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` affecting `line-height` in all browsers.
+ */
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sup {
+ top: -0.5em;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+/* Embedded content
+ ========================================================================== */
+
+/**
+ * Remove border when inside `a` element in IE 8/9/10.
+ */
+
+img {
+ border: 0;
+}
+
+/**
+ * Correct overflow not hidden in IE 9/10/11.
+ */
+
+svg:not(:root) {
+ overflow: hidden;
+}
+
+/* Grouping content
+ ========================================================================== */
+
+/**
+ * Address margin not present in IE 8/9 and Safari.
+ */
+
+figure {
+ margin: 1em 40px;
+}
+
+/**
+ * Address differences between Firefox and other browsers.
+ */
+
+hr {
+ -moz-box-sizing: content-box;
+ box-sizing: content-box;
+ height: 0;
+}
+
+/**
+ * Contain overflow in all browsers.
+ */
+
+pre {
+ overflow: auto;
+}
+
+/**
+ * Address odd `em`-unit font size rendering in all browsers.
+ */
+
+code,
+kbd,
+pre,
+samp {
+ font-family: monospace, monospace;
+ font-size: 1em;
+}
+
+/* Forms
+ ========================================================================== */
+
+/**
+ * Known limitation: by default, Chrome and Safari on OS X allow very limited
+ * styling of `select`, unless a `border` property is set.
+ */
+
+/**
+ * 1. Correct color not being inherited.
+ * Known issue: affects color of disabled elements.
+ * 2. Correct font properties not being inherited.
+ * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
+ */
+
+button,
+input,
+optgroup,
+select,
+textarea {
+ color: inherit; /* 1 */
+ font: inherit; /* 2 */
+ margin: 0; /* 3 */
+}
+
+/**
+ * Address `overflow` set to `hidden` in IE 8/9/10/11.
+ */
+
+button {
+ overflow: visible;
+}
+
+/**
+ * Address inconsistent `text-transform` inheritance for `button` and `select`.
+ * All other form control elements do not inherit `text-transform` values.
+ * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
+ * Correct `select` style inheritance in Firefox.
+ */
+
+button,
+select {
+ text-transform: none;
+}
+
+/**
+ * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
+ * and `video` controls.
+ * 2. Correct inability to style clickable `input` types in iOS.
+ * 3. Improve usability and consistency of cursor style between image-type
+ * `input` and others.
+ */
+
+button,
+html input[type="button"], /* 1 */
+input[type="reset"],
+input[type="submit"] {
+ cursor: pointer; /* 3 */
+}
+
+/**
+ * Re-set default cursor for disabled elements.
+ */
+
+button[disabled],
+html input[disabled] {
+ cursor: default;
+}
+
+/**
+ * Remove inner padding and border in Firefox 4+.
+ */
+
+button::-moz-focus-inner,
+input::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+
+/**
+ * Address Firefox 4+ setting `line-height` on `input` using `!important` in
+ * the UA stylesheet.
+ */
+
+input {
+ line-height: normal;
+}
+
+/**
+ * It's recommended that you don't attempt to style these elements.
+ * Firefox's implementation doesn't respect box-sizing, padding, or width.
+ *
+ * 1. Address box sizing set to `content-box` in IE 8/9/10.
+ * 2. Remove excess padding in IE 8/9/10.
+ */
+
+input[type="checkbox"],
+input[type="radio"] {
+ box-sizing: border-box; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/**
+ * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
+ * 2. Address `box-sizing` set to `border-box` in Safari and Chrome
+ * (include `-moz` to future-proof).
+ */
+
+input[type="search"] {
+ box-sizing: content-box;
+}
+
+/**
+ * Define consistent border, margin, and padding.
+ */
+
+fieldset {
+ border: 1px solid #c0c0c0;
+ margin: 0 2px;
+ padding: 0.35em 0.625em 0.75em;
+}
+
+/**
+ * 1. Correct `color` not being inherited in IE 8/9/10/11.
+ * 2. Remove padding so people aren't caught out if they zero out fieldsets.
+ */
+
+legend {
+ border: 0; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/**
+ * Remove default vertical scrollbar in IE 8/9/10/11.
+ */
+
+textarea {
+ overflow: auto;
+}
+
+/**
+ * Don't inherit the `font-weight` (applied by a rule above).
+ * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
+ */
+
+optgroup {
+ font-weight: bold;
+}
+
+/* Tables
+ ========================================================================== */
+
+/**
+ * Remove most spacing between table cells.
+ */
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+td,
+th {
+ padding: 0;
+}
+
+/* Normalization for FF panel defauts
+ ========================================================================== */
+html {
+ outline: none;
+ padding: 0;
+}
+
+a {
+ color: #0095dd;
+ margin: 0;
+ outline: none;
+ padding: 0;
+ text-decoration: none;
+}
+
+a:hover,
+a:active {
+ color: #008acb;
+ text-decoration: underline;
+}
+
+a:active {
+ color: #006b9d;
+}
diff --git a/browser/extensions/pocket/content/panels/css/saved.css b/browser/extensions/pocket/content/panels/css/saved.css
new file mode 100644
index 000000000..d3f88d04c
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/css/saved.css
@@ -0,0 +1,825 @@
+/* saved.css
+ *
+ * Description:
+ * With base elements out of the way, this sets all custom styling for the page saved dialog.
+ *
+ * Contents:
+ * Global
+ * Loading spinner
+ * Core detail
+ * Tag entry
+ * Recent/suggested tags
+ * Premium upsell
+ * Token input/autocomplete
+ * Overflow mode
+ * Language overrides
+ */
+
+/*=Global
+--------------------------------------------------------------------------------------- */
+.pkt_ext_containersaved {
+ background-color: #fbfbfb;
+ border-radius: 4px;
+ display: block;
+ font-size: 16px;
+ font-family: "FiraSans", "Helvetica Neue", Helvetica, Arial, sans-serif;
+ padding: 0;
+ position: relative;
+ text-align: center;
+}
+.pkt_ext_cf:after {
+ content: " ";
+ display:table;
+ clear:both;
+}
+.pkt_ext_containersaved .pkt_ext_tag_detail,
+.pkt_ext_containersaved .pkt_ext_recenttag_detail,
+.pkt_ext_containersaved .pkt_ext_suggestedtag_detail {
+ margin: 0 auto;
+ padding: 0.25em 1em;
+ position: relative;
+ width: auto;
+}
+
+/*=Loading spinner
+--------------------------------------------------------------------------------------- */
+@keyframes pkt_ext_spin {
+ to {
+ transform: rotate(1turn);
+ }
+}
+.pkt_ext_containersaved {
+ font-size: 16px;
+}
+.pkt_ext_containersaved .pkt_ext_loadingspinner {
+ position: relative;
+ display: inline-block;
+ height: 2.5em;
+ left: 50%;
+ margin: 2em 0 0 -1.25em;
+ font-size: 10px;
+ text-indent: 999em;
+ position: absolute;
+ top: 4em;
+ overflow: hidden;
+ width: 2.5em;
+ animation: pkt_ext_spin 0.7s infinite steps(8);
+}
+.pkt_ext_containersaved .pkt_ext_loadingspinner:before,
+.pkt_ext_containersaved .pkt_ext_loadingspinner:after,
+.pkt_ext_containersaved .pkt_ext_loadingspinner > div:before,
+.pkt_ext_containersaved .pkt_ext_loadingspinner > div:after {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 1.125em;
+ width: 0.25em;
+ height: 0.75em;
+ border-radius: .2em;
+ background: #eee;
+ box-shadow: 0 1.75em #eee;
+ transform-origin: 50% 1.25em;
+}
+.pkt_ext_containersaved .pkt_ext_loadingspinner:before {
+ background: #555;
+}
+.pkt_ext_containersaved .pkt_ext_loadingspinner:after {
+ transform: rotate(-45deg);
+ background: #777;
+}
+.pkt_ext_containersaved .pkt_ext_loadingspinner > div:before {
+ transform: rotate(-90deg);
+ background: #999;
+}
+.pkt_ext_containersaved .pkt_ext_loadingspinner > div:after {
+ transform: rotate(-135deg);
+ background: #bbb;
+}
+
+/*=Core detail
+--------------------------------------------------------------------------------------- */
+.pkt_ext_containersaved .pkt_ext_initload {
+ left: 0;
+ position: absolute;
+ top: 0;
+ width: 100%;
+}
+.pkt_ext_containersaved .pkt_ext_detail {
+ max-height: 0;
+ opacity: 0;
+ position: relative;
+ z-index: 10;
+}
+.pkt_ext_container_detailactive .pkt_ext_initload {
+ opacity: 0;
+}
+.pkt_ext_container_detailactive .pkt_ext_initload .pkt_ext_loadingspinner,
+.pkt_ext_container_finalstate .pkt_ext_initload .pkt_ext_loadingspinner {
+ animation: none;
+}
+.pkt_ext_container_detailactive .pkt_ext_detail {
+ max-height: 20em;
+ opacity: 1;
+}
+.pkt_ext_container_finalstate .pkt_ext_edit_msg,
+.pkt_ext_container_finalstate .pkt_ext_tag_detail,
+.pkt_ext_container_finalstate .pkt_ext_suggestedtag_detail,
+.pkt_ext_container_finalstate .pkt_ext_item_actions {
+ opacity: 0;
+ transition: opacity 0.2s ease-out;
+}
+.pkt_ext_container_finalerrorstate .pkt_ext_edit_msg,
+.pkt_ext_container_finalerrorstate .pkt_ext_tag_detail,
+.pkt_ext_container_finalerrorstate .pkt_ext_suggestedtag_detail,
+.pkt_ext_container_finalerrorstate .pkt_ext_item_actions {
+ display: none;
+ transition: none;
+}
+.pkt_ext_containersaved h2 {
+ background: transparent;
+ border: none;
+ color: #333;
+ display: block;
+ float: none;
+ font-size: 18px;
+ font-weight: normal;
+ letter-spacing: normal;
+ line-height: 1;
+ margin: 19px 0 4px;
+ padding: 0;
+ position: relative;
+ text-align: left;
+ text-transform: none;
+}
+@keyframes fade_in_out {
+ 0% {
+ opacity: 1;
+ }
+ 50% {
+ opacity: 0;
+ }
+ 100% {
+ opacity: 1;
+ }
+}
+.pkt_ext_container_finalstate h2 {
+ animation: fade_in_out 0.4s ease-out;
+}
+.pkt_ext_container_finalerrorstate h2 {
+ animation: none;
+ color: #d74345;
+}
+.pkt_ext_containersaved .pkt_ext_errordetail {
+ display: none;
+ font-size: 12px;
+ font-weight: normal;
+ left: 6.4em;
+ max-width: 21em;
+ opacity: 0;
+ position: absolute;
+ top: 2.7em;
+ text-align: left;
+ visibility: hidden;
+}
+.pkt_ext_container_finalerrorstate .pkt_ext_errordetail {
+ display: block;
+ opacity: 1;
+ visibility: visible;
+}
+.pkt_ext_containersaved .pkt_ext_logo {
+ background: url(../img/pocketlogosolo@1x.png) center center no-repeat;
+ display: block;
+ float: left;
+ height: 40px;
+ padding: 1.25em 1em;
+ position: relative;
+ width: 44px;
+}
+@media (min-resolution: 1.1dppx) {
+ .pkt_ext_containersaved .pkt_ext_logo {
+ background-image: url(../img/pocketlogosolo@2x.png);
+ background-size: 44px 40px;
+ }
+}
+.pkt_ext_container_finalerrorstate .pkt_ext_logo {
+ background-image: url(../img/pocketerror@1x.png);
+ height: 44px;
+ width: 44px;
+}
+@media (min-resolution: 1.1dppx) {
+ .pkt_ext_container_finalerrorstate .pkt_ext_logo {
+ background-image: url(../img/pocketerror@2x.png);
+ background-size: 44px 44px;
+ }
+}
+.pkt_ext_containersaved .pkt_ext_topdetail {
+ float: left;
+}
+.pkt_ext_containersaved .pkt_ext_edit_msg {
+ box-sizing: border-box;
+ display: none;
+ font-size: 0.75em;
+ left: auto;
+ padding: 0 1.4em;
+ position: absolute;
+ text-align: left;
+ top: 8.7em;
+ width: 100%;
+}
+.pkt_ext_containersaved .pkt_ext_edit_msg_error {
+ color: #d74345;
+}
+.pkt_ext_containersaved .pkt_ext_edit_msg_active {
+ display: block;
+}
+.pkt_ext_containersaved .pkt_ext_item_actions {
+ background: transparent;
+ float: none;
+ height: auto;
+ margin-bottom: 1em;
+ margin-top: 0;
+ width: auto;
+}
+.pkt_ext_containersaved .pkt_ext_item_actions_disabled {
+ opacity: 0.5;
+}
+.pkt_ext_container_finalstate .pkt_ext_item_actions_disabled {
+ opacity: 0;
+}
+.pkt_ext_containersaved .pkt_ext_item_actions ul {
+ background: none;
+ display: block;
+ float: none;
+ font-size: 16px;
+ height: auto;
+ margin: 0;
+ padding: 0;
+ width: 100%;
+}
+.pkt_ext_containersaved .pkt_ext_item_actions li {
+ box-sizing: border-box;
+ background: none;
+ border: 0;
+ float: left;
+ list-style: none;
+ line-height: 0.8;
+ height: auto;
+ padding-right: 0.4em;
+ width: auto;
+}
+.pkt_ext_containersaved .pkt_ext_item_actions li:before {
+ content: none;
+}
+.pkt_ext_containersaved .pkt_ext_item_actions .pkt_ext_actions_separator {
+ border-left: 2px solid #777;
+ height: 0.75em;
+ margin-top: 0.3em;
+ padding: 0;
+ width: 10px;
+}
+.pkt_ext_containersaved .pkt_ext_item_actions a {
+ background: transparent;
+ color: #0095dd;
+ display: block;
+ font-feature-settings: normal;
+ font-size: 12px;
+ font-weight: normal;
+ letter-spacing: normal;
+ line-height: inherit;
+ height: auto;
+ margin: 0;
+ padding: 0.5em;
+ float: left;
+ text-align: left;
+ text-decoration: none;
+ text-transform: none;
+}
+.pkt_ext_containersaved .pkt_ext_item_actions a:hover {
+ color: #008acb;
+ text-decoration: underline;
+}
+.pkt_ext_containersaved .pkt_ext_item_actions a:before,
+.pkt_ext_containersaved .pkt_ext_item_actions a:after {
+ background: transparent;
+ display: none;
+}
+.pkt_ext_containersaved .pkt_ext_item_actions_disabled a {
+ cursor: default;
+}
+.pkt_ext_containersaved .pkt_ext_item_actions .pkt_ext_openpocket {
+ float: right;
+ padding-right: 0.7em;
+ text-align: right;
+}
+.pkt_ext_containersaved .pkt_ext_item_actions .pkt_ext_removeitem {
+ padding-left: 0;
+}
+.pkt_ext_containersaved .pkt_ext_close {
+ background: url(../img/tag_close@1x.png) center center no-repeat;
+ color: #333;
+ display: block;
+ font-size: 0.8em;
+ height: 10px;
+ right: 0.5em;
+ overflow: hidden;
+ position: absolute;
+ text-align: center;
+ text-indent: -9999px;
+ top: -1em;
+ width: 10px;
+}
+@media (min-resolution: 1.1dppx) {
+ .pkt_ext_containersaved .pkt_ext_close {
+ background-image: url(../img/tag_close@2x.png);
+ background-size: 8px 8px;
+ }
+}
+.pkt_ext_containersaved .pkt_ext_close:hover {
+ color: #000;
+ text-decoration: none;
+}
+
+/*=Tag entry
+--------------------------------------------------------------------------------------- */
+.pkt_ext_containersaved .pkt_ext_tag_detail {
+ border: 1px solid #c1c1c1;
+ border-radius: 2px;
+ font-size: 16px;
+ clear: both;
+ margin: 1.25em 1em;
+ padding: 0;
+ display: flex;
+}
+.pkt_ext_containersaved .pkt_ext_tag_error {
+ border: none;
+}
+.pkt_ext_containersaved .pkt_ext_tag_input_wrapper {
+ box-sizing: border-box;
+ flex: 1;
+ background-color: #fff;
+ border-right: 1px solid #c3c3c3;
+ color: #333;
+ display: block;
+ float: none;
+ font-size: 0.875em;
+ list-style: none;
+ margin: 0;
+ overflow: hidden;
+ padding: 0.25em 0.5em;
+ width: 14em;
+ padding-left: 0.5em;
+ padding-right: 0.5em;
+}
+.pkt_ext_containersaved .pkt_ext_tag_error .pkt_ext_tag_input_wrapper {
+ border: 1px solid #d74345;
+}
+.pkt_ext_containersaved .pkt_ext_tag_input_wrapper .token-input-list {
+ display: block;
+ left: 0;
+ height: 1.7em;
+ overflow: hidden;
+ position: relative;
+ width: 60em;
+}
+.pkt_ext_containersaved .pkt_ext_tag_input_wrapper .token-input-list,
+.pkt_ext_containersaved .pkt_ext_tag_input_wrapper li {
+ font-size: 14px;
+}
+.pkt_ext_containersaved .pkt_ext_tag_input_wrapper li {
+ height: auto;
+ width: auto;
+}
+.pkt_ext_containersaved .pkt_ext_tag_input_wrapper li:before {
+ content: none;
+}
+.pkt_ext_containersaved .pkt_ext_tag_input_wrapper input {
+ border: 0;
+ box-shadow: none;
+ background-color: #fff;
+ color: #333;
+ font-size: 14px;
+ float: left;
+ line-height: normal;
+ height: auto;
+ min-height: 0;
+ min-width: 5em;
+ padding: 3px 2px 1px;
+ text-transform: none;
+}
+.pkt_ext_containersaved .pkt_ext_tag_input_wrapper input::placeholder {
+ color: #a9a9a9;
+ letter-spacing: normal;
+ text-transform: none;
+}
+.pkt_ext_containersaved .input_disabled {
+ cursor: default;
+ opacity: 0.5;
+}
+.pkt_ext_containersaved .pkt_ext_btn {
+ box-sizing: border-box;
+ color: #333;
+ float: none;
+ font-size: 0.875em;
+ font-size: 14px;
+ letter-spacing: normal;
+ height: 2.2em;
+ min-width: 4em;
+ padding: 0.5em 0;
+ text-decoration: none;
+ text-transform: none;
+ width: auto;
+}
+.pkt_ext_containersaved .pkt_ext_btn:hover {
+ background-color: #ebebeb;
+}
+.pkt_ext_containersaved .pkt_ext_btn:active {
+ background-color: #dadada;
+}
+.pkt_ext_containersaved .pkt_ext_btn_disabled,
+.pkt_ext_containersaved .pkt_ext_btn_disabled:hover,
+.pkt_ext_containersaved .pkt_ext_btn_disabled:active {
+ background-color: transparent;
+ cursor: default;
+ opacity: 0.4;
+}
+.pkt_ext_containersaved .pkt_ext_tag_error .pkt_ext_btn {
+ border: 1px solid #c3c3c3;
+ border-width: 1px 1px 1px 0;
+ height: 2.35em;
+}
+.pkt_ext_containersaved .autocomplete-suggestions {
+ margin-top: 2.2em;
+}
+
+/*=Recent/suggested tags
+--------------------------------------------------------------------------------------- */
+.pkt_ext_containersaved .pkt_ext_suggestedtag_detail,
+.pkt_ext_containersaved .pkt_ext_suggestedtag_detailshown {
+ border-top: 1px solid #c1c1c1;
+ bottom: 0;
+ box-sizing: border-box;
+ background: #ebebeb;
+ clear: both;
+ left: 0;
+ opacity: 0;
+ min-height: 110px;
+ position: fixed;
+ visibility: hidden;
+ width: 100%;
+}
+.pkt_ext_container_detailactive .pkt_ext_suggestedtag_detail,
+.pkt_ext_containersaved .pkt_ext_suggestedtag_detailshown {
+ opacity: 1;
+ visibility: visible;
+}
+.pkt_ext_containersaved .pkt_ext_suggestedtag_detailshown {
+ padding: 4px 0;
+}
+.pkt_ext_container_finalstate .pkt_ext_suggestedtag_detail {
+ opacity: 0;
+ visibility: hidden;
+}
+.pkt_ext_containersaved
+.pkt_ext_containersaved .pkt_ext_recenttag_detail h4,
+.pkt_ext_containersaved .pkt_ext_suggestedtag_detail h4 {
+ color: #333;
+ font-size: 0.8125em;
+ font-size: 13px;
+ font-weight: normal;
+ font-style: normal;
+ letter-spacing: normal;
+ margin: 0.5em 0;
+ text-align: left;
+ text-transform: none;
+}
+.pkt_ext_containersaved .pkt_ext_recenttag_detail .pkt_ext_loadingspinner,
+.pkt_ext_containersaved .pkt_ext_suggestedtag_detail .pkt_ext_loadingspinner {
+ display: none;
+ position: absolute;
+}
+.pkt_ext_containersaved .pkt_ext_recenttag_detail_loading .pkt_ext_loadingspinner,
+.pkt_ext_containersaved .pkt_ext_suggestedtag_detail_loading .pkt_ext_loadingspinner {
+ display: block;
+ font-size: 6px;
+ left: 48%;
+}
+.pkt_ext_containersaved .pkt_ext_recenttag_detail ul,
+.pkt_ext_containersaved .pkt_ext_suggestedtag_detail ul {
+ display: block;
+ margin: 0;
+ height: 2em;
+ overflow: hidden;
+ padding: 2px 0 0 0;
+}
+.pkt_ext_containersaved .pkt_ext_suggestedtag_detail ul {
+ height: auto;
+ margin: 0;
+ max-height: 4em;
+ padding-top: 6px;
+}
+.pkt_ext_containersaved .pkt_ext_recenttag_detail li,
+.pkt_ext_containersaved .pkt_ext_suggestedtag_detail li {
+ background: none;
+ float: left;
+ height: inherit;
+ line-height: 1.5;
+ list-style: none;
+ margin-bottom: 0.5em;
+ width: inherit;
+}
+.pkt_ext_containersaved .pkt_ext_recenttag_detail li:before,
+.pkt_ext_containersaved .pkt_ext_suggestedtag_detail li:before {
+ content: none;
+}
+.pkt_ext_containersaved .pkt_ext_recenttag_detail .recenttag_msg,
+.pkt_ext_containersaved .pkt_ext_suggestedtag_detail .suggestedtag_msg {
+ color: #333;
+ font-size: 0.8125em;
+ line-height: 1.2;
+ left: auto;
+ position: absolute;
+ text-align: left;
+ top: 2em;
+}
+.pkt_ext_containersaved .pkt_ext_suggestedtag_detail .suggestedtag_msg {
+ margin-right: 1.3em;
+}
+.pkt_ext_containersaved .token_tag {
+ border-radius: 4px;
+ background: #f7f7f7;
+ border: 1px solid #c3c3c3;
+ color: #333;
+ font-size: 0.875em;
+ font-size: 14px;
+ font-weight: normal;
+ letter-spacing: normal;
+ margin-right: 0.5em;
+ padding: 0.125em 0.625em;
+ text-decoration: none;
+ text-transform: none;
+}
+.pkt_ext_containersaved .token_tag:hover {
+ background-color: #008acb;
+ border-color: #008acb;
+ color: #fff;
+ text-decoration: none;
+}
+.pkt_ext_containersaved .token_tag:before,
+.pkt_ext_containersaved .token_tag:after {
+ content: none;
+}
+.pkt_ext_containersaved .token_tag:hover span {
+ background-image: url(../img/tag_closeactive@1x.png);
+}
+@media (min-resolution: 1.1dppx) {
+ .pkt_ext_containersaved .token_tag:hover span {
+ background-image: url(../img/tag_closeactive@2x.png);
+ background-size: 8px 8px;
+ }
+}
+.pkt_ext_containersaved .pkt_ext_recenttag_detail_disabled .token_tag,
+.pkt_ext_containersaved .pkt_ext_recenttag_detail_disabled .token_tag:hover,
+.pkt_ext_containersaved .pkt_ext_suggestedtag_detail_disabled .token_tag,
+.pkt_ext_containersaved .pkt_ext_suggestedtag_detail_disabled .token_tag:hover {
+ background-color: #f7f7f7;
+ cursor: default;
+ opacity: 0.5;
+}
+.pkt_ext_containersaved .token_tag_inactive {
+ display: none;
+}
+
+/*=Premium upsell
+--------------------------------------------------------------------------------------- */
+.pkt_ext_detail .pkt_ext_premupsell {
+ background-color: #50bbb6;
+ display: block;
+ padding: 1.5em 0;
+ text-align: center;
+}
+.pkt_ext_premupsell h4 {
+ color: #fff;
+ font-size: 1em;
+ margin-bottom: 1em;
+}
+.pkt_ext_premupsell a {
+ color: #28605d;
+ border-bottom: 1px solid #47a7a3;
+ font-weight: normal;
+}
+.pkt_ext_premupsell a:hover {
+ color: #14302f;
+}
+
+/*=Token input/autocomplete
+--------------------------------------------------------------------------------------- */
+.token-input-dropdown-tag {
+ border-radius: 4px;
+ box-sizing: border-box;
+ background: #fff;
+ border: 1px solid #cdcdcd;
+ margin-top: 0.5em;
+ left: 0 !important;
+ overflow-y: auto;
+ top: 1.9em !important;
+ z-index: 9000;
+}
+.token-input-dropdown-tag ul {
+ height: inherit;
+ max-height: 115px;
+ margin: 0;
+ overflow: auto;
+ padding: 0.5em 0;
+}
+.token-input-dropdown-tag ul li {
+ background: none;
+ color: #333;
+ font-weight: normal;
+ font-size: 1em;
+ float: none;
+ height: inherit;
+ letter-spacing: normal;
+ list-style: none;
+ padding: 0.75em;
+ text-align: left;
+ text-transform: none;
+ width: inherit;
+}
+.token-input-dropdown-tag ul li:before {
+ content: none;
+}
+.token-input-dropdown ul li.token-input-selected-dropdown-item {
+ background-color: #008acb;
+ color: #fff;
+}
+.token-input-list {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+}
+.token-input-list li {
+ text-align: left;
+ list-style: none;
+}
+.token-input-list li input {
+ border: 0;
+ background-color: white;
+}
+.pkt_ext_containersaved .token-input-token {
+ background: none;
+ border-radius: 4px;
+ border: 1px solid #c3c3c3;
+ overflow: hidden;
+ margin: 0;
+ padding: 0 8px;
+ background-color: #f7f7f7;
+ color: #000;
+ font-weight: normal;
+ cursor: default;
+ line-height: 1.5;
+ display: block;
+ width: auto;
+ margin: 0 0.2em;
+ float: left;
+}
+.pkt_ext_containersaved .pkt_ext_tag_input_wrapper_disabled {
+ position: relative;
+}
+.pkt_ext_containersaved .pkt_ext_tag_input_wrapper_disabled input {
+ opacity: 0.5;
+}
+.pkt_ext_containersaved .pkt_ext_tag_input_wrapper_disabled .token-input-list {
+ opacity: 0.5;
+}
+.pkt_ext_containersaved .pkt_ext_tag_input_wrapper_disabled .pkt_ext_tag_input_blocker {
+ height: 100%;
+ left: 0;
+ position: absolute;
+ top: 0;
+ width: 100%;
+ z-index: 5;
+}
+.pkt_ext_containersaved .token-input-token p {
+ display: inline-block;
+ font-size: 14px;
+ font-weight: normal;
+ line-height: inherit;
+ letter-spacing: normal;
+ padding: 0;
+ margin: 0;
+ text-transform: none;
+ vertical-align: top;
+ width: auto;
+}
+.pkt_ext_containersaved .token-input-token p:before {
+ content: none;
+ width: 0;
+}
+.pkt_ext_containersaved .token-input-token span {
+ background: url(../img/tag_close@1x.png) center center no-repeat;
+ cursor: pointer;
+ display: inline-block;
+ height: 8px;
+ margin: 0 0 0 8px;
+ overflow: hidden;
+ width: 8px;
+ text-indent: -99px;
+}
+@media (min-resolution: 1.1dppx) {
+ .pkt_ext_containersaved .token-input-token span {
+ background-image: url(../img/tag_close@2x.png);
+ background-size: 8px 8px;
+ }
+}
+.pkt_ext_containersaved .token-input-selected-token {
+ background-color: #008acb;
+ border-color: #008acb;
+ color: #fff;
+}
+.pkt_ext_containersaved .token-input-selected-token span {
+ background-image: url(../img/tag_closeactive@1x.png);
+}
+@media (min-resolution: 1.1dppx) {
+ .pkt_ext_containersaved .token-input-selected-token span {
+ background-image: url(../img/tag_closeactive@2x.png);
+ background-size: 8px 8px;
+ }
+}
+.pkt_ext_containersaved .pkt_ext_tag_input_wrapper_disabled .token-input-selected-token {
+ background-color: #f7f7f7;
+}
+.pkt_ext_containersaved .pkt_ext_tag_input_wrapper_disabled .token-input-selected-token span {
+ color: #bbb;
+}
+
+/*=Overflow mode
+--------------------------------------------------------------------------------------- */
+.pkt_ext_saved_overflow .pkt_ext_logo {
+ float: none;
+ margin: 0.5em auto 0;
+}
+.pkt_ext_saved_overflow .pkt_ext_initload {
+ top: -8px;
+}
+.pkt_ext_saved_overflow .pkt_ext_loadingspinner {
+ top: 10em;
+}
+.pkt_ext_saved_overflow .pkt_ext_topdetail {
+ float: none;
+ margin: 0 auto;
+ padding: 0 1em;
+}
+.pkt_ext_saved_overflow h2 {
+ margin-bottom: 0.5em;
+ margin-top: 0;
+ text-align: center;
+}
+.pkt_ext_saved_overflow .pkt_ext_item_actions ul {
+ display: inline-block;
+ width: auto;
+}
+.pkt_ext_saved_overflow .pkt_ext_item_actions li {
+ float: none;
+ padding-left: 1em;
+ padding-right: 1em;
+ text-align: center;
+}
+.pkt_ext_saved_overflow .pkt_ext_item_actions .pkt_ext_removeitem,
+.pkt_ext_saved_overflow .pkt_ext_item_actions .pkt_ext_openpocket {
+ float: none;
+ text-align: center;
+ padding-left: 0;
+ padding-right: 0;
+}
+.pkt_ext_saved_overflow .pkt_ext_item_actions .pkt_ext_actions_separator {
+ display: none;
+}
+.pkt_ext_saved_overflow .pkt_ext_tag_detail {
+ margin-top: 0;
+}
+.pkt_ext_saved_overflow .pkt_ext_suggestedtag_detail,
+.pkt_ext_saved_overflow .pkt_ext_suggestedtag_detailshown {
+ top: 14.75em;
+}
+.pkt_ext_saved_overflow .pkt_ext_edit_msg {
+ top: 16em;
+}
+.pkt_ext_container_finalerrorstate.pkt_ext_saved_overflow .pkt_ext_errordetail {
+ box-sizing: border-box;
+ left: 0;
+ padding-left: 1em;
+ padding-right: 1em;
+ text-align: center;
+ top: 8.3em;
+ width: 100%;
+}
+
+/*=Language overrides
+--------------------------------------------------------------------------------------- */
+.pkt_ext_saved_es .pkt_ext_btn {
+ min-width: 5em;
+}
+.pkt_ext_saved_de .pkt_ext_btn,
+.pkt_ext_saved_ru .pkt_ext_btn {
+ min-width: 6em;
+}
diff --git a/browser/extensions/pocket/content/panels/css/signup.css b/browser/extensions/pocket/content/panels/css/signup.css
new file mode 100644
index 000000000..5c428a29b
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/css/signup.css
@@ -0,0 +1,424 @@
+/* signup.css
+ *
+ * Description:
+ * With base elements out of the way, this sets all custom styling for the extension.
+ *
+ * Contents:
+ * Global
+ * Core detail
+ * Core detail - storyboard
+ * Buttons
+ * Overflow mode
+ * Language overrides
+ */
+
+/*=Global
+--------------------------------------------------------------------------------------- */
+.pkt_ext_containersignup {
+ background-color: #ebebeb;
+ color: #333;
+ display: block;
+ font-size: 16px;
+ font-family: "FiraSans", "Helvetica Neue", Helvetica, Arial, sans-serif;
+ margin: 0;
+ padding: 0;
+ position: relative;
+ text-align: center;
+}
+.pkt_ext_containersignup_inactive {
+ animation: pkt_ext_hide 0.3s ease-out;
+ opacity: 0;
+ visibility: hidden;
+}
+.pkt_ext_cf:after {
+ content: " ";
+ display: table;
+ clear: both;
+}
+@keyframes pkt_ext_hide {
+ 0% {
+ opacity: 1;
+ visibility: visible;
+ }
+ 99% {
+ opacity: 0;
+ visibility: visible;
+ }
+ 100% {
+ opacity: 0;
+ visibility: hidden;
+ }
+}
+
+/*=Core detail
+--------------------------------------------------------------------------------------- */
+.pkt_ext_containersignup p {
+ font-size: 14px;
+ color: #333;
+ font-family: "FiraSans", "Helvetica Neue", Helvetica, Arial, sans-serif;
+ line-height: 1.3;
+ margin: 0 auto 1.5em;
+ max-width: 260px;
+}
+.pkt_ext_containersignup a {
+ color: #4c8fd0;
+}
+.pkt_ext_containersignup a:hover {
+ color: #3076b9;
+}
+.pkt_ext_containersignup .pkt_ext_introdetail {
+ background-color: #fbfbfb;
+ border: 1px solid #c1c1c1;
+ border-width: 0 0 1px;
+}
+.pkt_ext_containersignup .pkt_ext_logo {
+ background: url(../img/pocketlogo@1x.png) center bottom no-repeat;
+ display: block;
+ height: 32px;
+ margin: 0 auto 15px;
+ padding-top: 25px;
+ position: relative;
+ text-indent: -9999px;
+ width: 123px;
+}
+@media (min-resolution: 1.1dppx) {
+ .pkt_ext_containersignup .pkt_ext_logo {
+ background-image: url(../img/pocketlogo@2x.png);
+ background-size: 123px 32px;
+ }
+}
+.pkt_ext_containersignup .pkt_ext_introimg {
+ background: url(../img/pocketsignup_hero@1x.png) center center no-repeat;
+ display: block;
+ height: 125px;
+ margin: 0 auto;
+ position: relative;
+ text-indent: -9999px;
+ width: 255px;
+}
+@media (min-resolution: 1.1dppx) {
+ .pkt_ext_containersignup .pkt_ext_introimg {
+ background-image: url(../img/pocketsignup_hero@2x.png);
+ background-size: 255px 125px;
+ }
+}
+.pkt_ext_containersignup .pkt_ext_tagline {
+ margin-bottom: 0.5em;
+}
+.pkt_ext_containersignup .pkt_ext_learnmore {
+ font-size: 12px;
+}
+.pkt_ext_containersignup .pkt_ext_learnmoreinactive {
+ visibility: hidden;
+}
+.pkt_ext_signupdetail h4 {
+ font-size: 12px;
+ font-weight: normal;
+}
+.pkt_ext_signupdetail .btn-container {
+ position: relative;
+ margin-bottom: 0.8em;
+}
+.pkt_ext_containersignup .ff_signuphelp {
+ background: url(../img/signup_help@1x.png) center center no-repeat;
+ display: block;
+ height: 18px;
+ margin-top: -9px;
+ right: -15px;
+ position: absolute;
+ text-indent: -9999px;
+ width: 18px;
+ top: 50%;
+}
+@media (min-resolution: 1.1dppx) {
+ .pkt_ext_containersignup .ff_signuphelp {
+ background-image: url(../img/signup_help@2x.png);
+ background-size: 18px 18px;
+ }
+}
+.pkt_ext_containersignup .alreadyhave {
+ font-size: 12px;
+ max-width: 320px;
+ margin-top: 15px;
+}
+.pkt_ext_containersignup .tryitnowspace {
+ margin-top: 22px;
+}
+.pkt_ext_signupdetail p.pkt_ext_tos {
+ color: #777;
+ font-size: 10px;
+ line-height: 1.5;
+ margin-top: 17px;
+ padding-top: 0;
+ max-width: 190px;
+}
+
+/*=Core detail - storyboard
+--------------------------------------------------------------------------------------- */
+.pkt_ext_introstory {
+ align-items: center;
+ display: flex;
+ padding: 20px;
+}
+.pkt_ext_introstory:after {
+ clear: both;
+ content: "";
+ display: table;
+}
+.pkt_ext_introstory p {
+ margin-bottom: 0;
+ text-align: left;
+}
+.pkt_ext_introstoryone {
+ padding: 20px 18px 15px 20px;
+}
+.pkt_ext_introstorytwo {
+ padding: 3px 0 0 20px;
+}
+.pkt_ext_introstorytwo .pkt_ext_tagline {
+ margin-bottom: 1.5em;
+}
+.pkt_ext_introstory_text {
+ flex: 1;
+}
+.pkt_ext_introstoryone_img,
+.pkt_ext_introstorytwo_img {
+ display: block;
+ overflow: hidden;
+ position: relative;
+ text-indent: -999px;
+}
+.pkt_ext_introstoryone_img {
+ background: url(../img/pocketsignup_button@1x.png) center right no-repeat;
+ height: 82px;
+ padding: 0 0 0 0.7em;
+ width: 82px;
+}
+@media (min-resolution: 1.1dppx) {
+ .pkt_ext_introstoryone_img {
+ background-image: url(../img/pocketsignup_button@2x.png);
+ background-size: 82px 82px;
+ }
+}
+.pkt_ext_introstorytwo_img {
+ background: url(../img/pocketsignup_devices@1x.png) bottom right no-repeat;
+ height: 110px;
+ padding: 1em 0 0 0.7em;
+ width: 124px;
+}
+@media (min-resolution: 1.1dppx) {
+ .pkt_ext_introstorytwo_img {
+ background-image: url(../img/pocketsignup_devices@2x.png);
+ background-size: 124px 110px;
+ }
+}
+.pkt_ext_introstorydivider {
+ border-top: 1px solid #c1c1c1;
+ height: 1px;
+ margin: 0 auto;
+ width: 125px;
+}
+
+/*=Buttons
+--------------------------------------------------------------------------------------- */
+.pkt_ext_containersignup .btn {
+ background-color: #0096dd;
+ border: 1px solid #0095dd;
+ border-radius: 2px;
+ color: #fff;
+ display: inline-block;
+ font-family: "FiraSans", "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 16px;
+ font-weight: normal;
+ line-height: 1;
+ margin: 0;
+ padding: 11px 45px;
+ text-align: center;
+ text-decoration: none;
+ text-shadow: 0 -1px 0 rgba(142,4,17,0.5);
+ transition: background-color 0.1s linear;
+ width: auto;
+}
+.pkt_ext_containersignup .btn-secondary {
+ background-color: #fbfbfb;
+ border-color: #c1c1c1;
+ color: #444;
+ text-shadow: 0 1px 0 rgba(255,255,255,0.5);
+}
+.pkt_ext_containersignup .btn-small {
+ padding: 6px 20px;
+}
+.pkt_ext_containersignup .btn-mini {
+ font-size: 14px;
+ padding: 5px 15px 4px;
+}
+.pkt_ext_containersignup .btn:hover {
+ background-color: #008acb;
+ color: #fff;
+ text-decoration: none;
+}
+.pkt_ext_containersignup .btn-secondary:hover,
+.pkt_ext_containersignup .btn-important:hover {
+ background-color: #f6f6f6;
+ color: #222;
+}
+.pkt_ext_containersignup .btn-disabled {
+ background-image: none;
+ color: #ccc;
+ color: rgba(255,255,255,0.6);
+ cursor: default;
+ opacity: 0.9;
+}
+.pkt_ext_containersignup .signup-btn-firefox,
+.pkt_ext_containersignup .signup-btn-tryitnow,
+.pkt_ext_containersignup .signup-btn-email,
+.pkt_ext_containersignup .signupinterim-btn-login,
+.pkt_ext_containersignup .signupinterim-btn-signup,
+.pkt_ext_containersignup .forgot-btn-submit,
+.pkt_ext_containersignup .forgotreset-btn-change {
+ min-width: 12.125em;
+ padding: 0.8em 1.1875em;
+ box-sizing: content-box;
+}
+.pkt_ext_containersignup .signup-btn-email {
+ position: relative;
+ z-index: 10;
+}
+.pkt_ext_containersignup .signup-btn-tryitnow,
+.pkt_ext_containersignup .signup-btn-firefox {
+ min-width: 14.5em;
+ position: relative;
+ padding: 0;
+}
+.pkt_ext_containersignup .signup-btn-tryitnow{
+ margin-top: 25px;
+}
+.pkt_ext_containersignup .signup-btn-firefox .logo {
+ background: url(../img/signup_firefoxlogo@1x.png) center center no-repeat;
+ height: 2.6em;
+ left: 10px;
+ margin: 0;
+ padding: 0;
+ width: 22px;
+ position: absolute;
+}
+@media (min-resolution: 1.1dppx) {
+ .pkt_ext_containersignup .signup-btn-firefox .logo {
+ background-image: url(../img/signup_firefoxlogo@2x.png);
+ background-size: 22px 22px;
+ }
+}
+.pkt_ext_containersignup .forgotreset-btn-change {
+ margin-bottom: 2em;
+}
+.pkt_ext_containersignup .signup-btn-tryitnow .text,
+.pkt_ext_containersignup .signup-btn-firefox .text {
+ display: inline-block;
+ padding: 0.8em 1.625em;
+ position: relative;
+ text-shadow: none;
+ white-space: nowrap;
+}
+.pkt_ext_containersignup .signup-btn-tryitnow .text,
+.pkt_ext_containersignup .signup-btn-firefox .text {
+ color: #fff;
+}
+.pkt_ext_containersignup .btn-disabled .text {
+ color: #ccc;
+ color: rgba(255,255,255,0.6);
+}
+
+/*=Overflow mode
+--------------------------------------------------------------------------------------- */
+.pkt_ext_signup_overflow .pkt_ext_tagline {
+ margin-bottom: 1em;
+ padding: 0 1em;
+}
+.pkt_ext_signup_overflow .pkt_ext_introimg {
+ background-size: 200px 98px;
+ height: 98px;
+ width: 200px;
+}
+.pkt_ext_signup_overflow .signup-btn-firefox,
+.pkt_ext_containersignup .signup-btn-tryitnow,
+.pkt_ext_signup_overflow .signup-btn-email {
+ font-size: 14px;
+ min-width: 12.6em;
+ padding-left: 0.75em;
+ padding-right: 0.75em;
+}
+.pkt_ext_signup_overflow .signup-btn-tryitnow .text,
+.pkt_ext_signup_overflow .signup-btn-firefox .text {
+ padding-left: 0;
+ padding-right: 0;
+}
+
+/*=Language overrides
+--------------------------------------------------------------------------------------- */
+.pkt_ext_signup_de .pkt_ext_introstoryone_img {
+ margin-right: -5px;
+ padding-left: 0;
+}
+.pkt_ext_signup_de .pkt_ext_introstorytwo .pkt_ext_tagline,
+.pkt_ext_signup_es .pkt_ext_introstorytwo .pkt_ext_tagline,
+.pkt_ext_signup_ja .pkt_ext_introstorytwo .pkt_ext_tagline,
+.pkt_ext_signup_ru .pkt_ext_introstorytwo .pkt_ext_tagline {
+ margin-bottom: 0.5em;
+}
+.pkt_ext_signup_de .signup-btn-firefox .text,
+.pkt_ext_signup_de .signup-btn-tryitnow .text,
+.pkt_ext_signup_de .signup-btn-email,
+.pkt_ext_signup_es .pkt_ext_signupdetail_hero .signup-btn-firefox .text,
+.pkt_ext_signup_es .pkt_ext_signupdetail_hero .signup-btn-email,
+.pkt_ext_signup_ja .signup-btn-firefox .text,
+.pkt_ext_signup_ja .signup-btn-tryitnow .text,
+.pkt_ext_signup_ja .signup-btn-email,
+.pkt_ext_signup_ru .signup-btn-firefox .text,
+.pkt_ext_signup_ru .signup-btn-tryitnow .text,
+.pkt_ext_signup_ru .signup-btn-email {
+ font-size: 15px;
+}
+.pkt_ext_signup_ja .signup-btn-firefox .text,
+.pkt_ext_signup_ja .signup-btn-tryitnow .text,
+.pkt_ext_signup_ru .signup-btn-firefox .text,
+.pkt_ext_signup_ru .signup-btn-tryitnow .text {
+ left: 15px;
+}
+.pkt_ext_signup_de .signup-btn-firefox .logo,
+.pkt_ext_signup_es .pkt_ext_signupdetail_hero .signup-btn-firefox .logo,
+.pkt_ext_signup_ja .signup-btn-firefox .logo,
+.pkt_ext_signup_ru .signup-btn-firefox .logo {
+ height: 2.4em;
+}
+@media (min-resolution: 1.1dppx) {
+ .pkt_ext_signup_de .signup-btn-firefox .logo,
+ .pkt_ext_signup_es .pkt_ext_signupdetail_hero .signup-btn-firefox .logo,
+ .pkt_ext_signup_ja .signup-btn-firefox .logo,
+ .pkt_ext_signup_ru .signup-btn-firefox .logo {
+ height: 2.5em;
+ }
+}
+.pkt_ext_signup_de .signup-btn-email,
+.pkt_ext_signup_es .pkt_ext_signupdetail_hero .signup-btn-email,
+.pkt_ext_signup_ja .signup-btn-email,
+.pkt_ext_signup_ru .signup-btn-email {
+ min-width: 13em;
+ padding: 0.8533em 1.2667em;
+}
+.pkt_ext_signup_de .pkt_ext_logo,
+.pkt_ext_signup_es .pkt_ext_logo,
+.pkt_ext_signup_ru .pkt_ext_logo {
+ padding-top: 15px;
+}
+.pkt_ext_signup_de .pkt_ext_introdetailhero .pkt_ext_tagline,
+.pkt_ext_signup_es .pkt_ext_introdetailhero .pkt_ext_tagline,
+.pkt_ext_signup_ja .pkt_ext_introdetailhero .pkt_ext_tagline,
+.pkt_ext_signup_ru .pkt_ext_introdetailhero .pkt_ext_tagline {
+ font-size: 13px;
+}
+.pkt_ext_signup_overflow.pkt_ext_signup_de .signup-btn-firefox .logo,
+.pkt_ext_signup_overflow.pkt_ext_signup_es .signup-btn-firefox .logo,
+.pkt_ext_signup_overflow.pkt_ext_signup_ja .signup-btn-firefox .logo,
+.pkt_ext_signup_overflow.pkt_ext_signup_ru .signup-btn-firefox .logo {
+ display: none;
+}
diff --git a/browser/extensions/pocket/content/panels/fonts/FiraSans-Regular.woff b/browser/extensions/pocket/content/panels/fonts/FiraSans-Regular.woff
new file mode 100644
index 000000000..f466cdda9
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/fonts/FiraSans-Regular.woff
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/pocket.svg b/browser/extensions/pocket/content/panels/img/pocket.svg
new file mode 100644
index 000000000..d93fd6a15
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/pocket.svg
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24">
+ <style>
+ use:not(:target) {
+ display: none;
+ }
+ use {
+ fill: #808080;
+ }
+ use[id$="-added"] {
+ fill: #ee4056;
+ }
+ </style>
+ <defs>
+ <path id="pocket-mark-shape" d="M21.901,4.204C21.642,3.484,20.956,3,20.196,3h-0.01h-1.721H3.814C3.067,3,2.385,3.474,2.119,4.179 C2.04,4.388,2,4.606,2,4.828v6.082l0.069,1.21c0.29,2.751,1.707,5.155,3.899,6.832c0.039,0.03,0.079,0.06,0.119,0.089l0.025,0.018 c1.175,0.866,2.491,1.452,3.91,1.741C10.677,20.932,11.347,21,12.013,21c0.615,0,1.232-0.057,1.839-0.171 c0.073-0.014,0.145-0.028,0.219-0.044c0.02-0.004,0.042-0.012,0.064-0.023c1.359-0.299,2.621-0.87,3.753-1.704l0.025-0.018 c0.04-0.029,0.08-0.059,0.119-0.089c2.192-1.677,3.609-4.08,3.898-6.832L22,10.91V4.828C22,4.618,21.975,4.409,21.901,4.204z M17.667,10.539l-4.704,4.547c-0.266,0.256-0.608,0.385-0.949,0.385c-0.342,0-0.684-0.129-0.949-0.385l-4.705-4.547 c-0.547-0.528-0.565-1.403-0.04-1.954c0.524-0.551,1.392-0.569,1.939-0.041l3.756,3.63l3.755-3.63 c0.547-0.528,1.415-0.51,1.939,0.04C18.231,9.136,18.213,10.011,17.667,10.539z"/>
+ </defs>
+ <use id="pocket-mark" xlink:href="#pocket-mark-shape"/>
+ <use id="pocket-mark-added" xlink:href="#pocket-mark-shape"/>
+</svg>
diff --git a/browser/extensions/pocket/content/panels/img/pocketerror@1x.png b/browser/extensions/pocket/content/panels/img/pocketerror@1x.png
new file mode 100644
index 000000000..e2b4d04de
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/pocketerror@1x.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/pocketerror@2x.png b/browser/extensions/pocket/content/panels/img/pocketerror@2x.png
new file mode 100644
index 000000000..d501503b0
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/pocketerror@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/pocketlogo@1x.png b/browser/extensions/pocket/content/panels/img/pocketlogo@1x.png
new file mode 100644
index 000000000..62b3db310
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/pocketlogo@1x.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/pocketlogo@2x.png b/browser/extensions/pocket/content/panels/img/pocketlogo@2x.png
new file mode 100644
index 000000000..b0e80bff3
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/pocketlogo@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/pocketlogosolo@1x.png b/browser/extensions/pocket/content/panels/img/pocketlogosolo@1x.png
new file mode 100644
index 000000000..77dc16f8c
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/pocketlogosolo@1x.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/pocketlogosolo@2x.png b/browser/extensions/pocket/content/panels/img/pocketlogosolo@2x.png
new file mode 100644
index 000000000..c467c5a29
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/pocketlogosolo@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/pocketmenuitem16.png b/browser/extensions/pocket/content/panels/img/pocketmenuitem16.png
new file mode 100644
index 000000000..b52db6abf
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/pocketmenuitem16.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/pocketmenuitem16@2x.png b/browser/extensions/pocket/content/panels/img/pocketmenuitem16@2x.png
new file mode 100644
index 000000000..69aa55b03
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/pocketmenuitem16@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/pocketsignup_button@1x.png b/browser/extensions/pocket/content/panels/img/pocketsignup_button@1x.png
new file mode 100644
index 000000000..12326fae3
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/pocketsignup_button@1x.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/pocketsignup_button@2x.png b/browser/extensions/pocket/content/panels/img/pocketsignup_button@2x.png
new file mode 100644
index 000000000..5bdebc5e9
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/pocketsignup_button@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/pocketsignup_devices@1x.png b/browser/extensions/pocket/content/panels/img/pocketsignup_devices@1x.png
new file mode 100644
index 000000000..c4a7ad677
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/pocketsignup_devices@1x.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/pocketsignup_devices@2x.png b/browser/extensions/pocket/content/panels/img/pocketsignup_devices@2x.png
new file mode 100644
index 000000000..157304c3e
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/pocketsignup_devices@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/pocketsignup_hero@1x.png b/browser/extensions/pocket/content/panels/img/pocketsignup_hero@1x.png
new file mode 100644
index 000000000..80c5bd486
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/pocketsignup_hero@1x.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/pocketsignup_hero@2x.png b/browser/extensions/pocket/content/panels/img/pocketsignup_hero@2x.png
new file mode 100644
index 000000000..36d0add61
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/pocketsignup_hero@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/signup_firefoxlogo@1x.png b/browser/extensions/pocket/content/panels/img/signup_firefoxlogo@1x.png
new file mode 100644
index 000000000..52cbe052c
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/signup_firefoxlogo@1x.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/signup_firefoxlogo@2x.png b/browser/extensions/pocket/content/panels/img/signup_firefoxlogo@2x.png
new file mode 100644
index 000000000..cd218805e
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/signup_firefoxlogo@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/signup_help@1x.png b/browser/extensions/pocket/content/panels/img/signup_help@1x.png
new file mode 100644
index 000000000..5019025c0
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/signup_help@1x.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/signup_help@2x.png b/browser/extensions/pocket/content/panels/img/signup_help@2x.png
new file mode 100644
index 000000000..6714bb3bc
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/signup_help@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/signup_or@1x.png b/browser/extensions/pocket/content/panels/img/signup_or@1x.png
new file mode 100644
index 000000000..318cea0f6
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/signup_or@1x.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/signup_or@2x.png b/browser/extensions/pocket/content/panels/img/signup_or@2x.png
new file mode 100644
index 000000000..837f1814a
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/signup_or@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/tag_close@1x.png b/browser/extensions/pocket/content/panels/img/tag_close@1x.png
new file mode 100644
index 000000000..2dd02ba02
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/tag_close@1x.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/tag_close@2x.png b/browser/extensions/pocket/content/panels/img/tag_close@2x.png
new file mode 100644
index 000000000..8bd0eec57
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/tag_close@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/tag_closeactive@1x.png b/browser/extensions/pocket/content/panels/img/tag_closeactive@1x.png
new file mode 100644
index 000000000..ad4239232
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/tag_closeactive@1x.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/img/tag_closeactive@2x.png b/browser/extensions/pocket/content/panels/img/tag_closeactive@2x.png
new file mode 100644
index 000000000..80c35e3aa
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/img/tag_closeactive@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/content/panels/js/messages.js b/browser/extensions/pocket/content/panels/js/messages.js
new file mode 100644
index 000000000..ae08c3e73
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/js/messages.js
@@ -0,0 +1,78 @@
+// Documentation of methods used here are at:
+// https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Interaction_between_privileged_and_non-privileged_pages
+
+var pktPanelMessaging = (function() {
+
+ function panelIdFromURL(url) {
+ var panelId = url.match(/panelId=([\w|\d|\.]*)&?/);
+ if (panelId && panelId.length > 1) {
+ return panelId[1];
+ }
+
+ return 0;
+ }
+
+ function prefixedMessageId(messageId) {
+ return 'PKT_' + messageId;
+ }
+
+ function panelPrefixedMessageId(panelId, messageId) {
+ return prefixedMessageId(panelId + '_' + messageId);
+ }
+
+ function addMessageListener(panelId, messageId, callback) {
+ document.addEventListener(panelPrefixedMessageId(panelId, messageId), function(e) {
+
+ callback(JSON.parse(e.target.getAttribute("payload"))[0]);
+
+ // TODO: Figure out why e.target.parentNode is null
+ // e.target.parentNode.removeChild(e.target);
+
+ }, false);
+
+ }
+
+ function removeMessageListener(panelId, messageId, callback) {
+ document.removeEventListener(panelPrefixedMessageId(panelId, messageId), callback);
+ }
+
+ function sendMessage(panelId, messageId, payload, callback) {
+ // Payload needs to be an object in format:
+ // { panelId: panelId, data: {} }
+ var messagePayload = {
+ panelId: panelId,
+ data: (payload || {})
+ };
+
+ // Create a callback to listen for a response
+ if (callback) {
+ var messageResponseId = messageId + "Response";
+ var responseListener = function(responsePayload) {
+ callback(responsePayload);
+ removeMessageListener(panelId, messageResponseId, responseListener);
+ }
+
+ addMessageListener(panelId, messageResponseId, responseListener);
+ }
+
+ // Send message
+ var element = document.createElement("PKTMessageFromPanelElement");
+ element.setAttribute("payload", JSON.stringify([messagePayload]));
+ document.documentElement.appendChild(element);
+
+ var evt = document.createEvent("Events");
+ evt.initEvent(prefixedMessageId(messageId), true, false);
+ element.dispatchEvent(evt);
+ }
+
+
+ /**
+ * Public functions
+ */
+ return {
+ panelIdFromURL: panelIdFromURL,
+ addMessageListener : addMessageListener,
+ removeMessageListener : removeMessageListener,
+ sendMessage: sendMessage
+ };
+}());
diff --git a/browser/extensions/pocket/content/panels/js/saved.js b/browser/extensions/pocket/content/panels/js/saved.js
new file mode 100644
index 000000000..3abc8889a
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/js/saved.js
@@ -0,0 +1,608 @@
+/*
+PKT_SAVED_OVERLAY is the view itself and contains all of the methods to manipute the overlay and messaging.
+It does not contain any logic for saving or communication with the extension or server.
+*/
+var PKT_SAVED_OVERLAY = function (options)
+{
+ var myself = this;
+ this.inited = false;
+ this.active = false;
+ this.wrapper = null;
+ this.pockethost = "getpocket.com";
+ this.savedItemId = 0;
+ this.savedUrl = '';
+ this.premiumStatus = false;
+ this.preventCloseTimerCancel = false;
+ this.closeValid = true;
+ this.mouseInside = false;
+ this.autocloseTimer = null;
+ this.inoverflowmenu = false;
+ this.dictJSON = {};
+ this.autocloseTiming = 3500;
+ this.autocloseTimingFinalState = 2000;
+ this.mouseInside = false;
+ this.userTags = [];
+ this.cxt_suggested_available = 0;
+ this.cxt_entered = 0;
+ this.cxt_suggested = 0;
+ this.cxt_removed = 0;
+ this.justaddedsuggested = false;
+ this.fillTagContainer = function(tags, container, tagclass) {
+ container.children().remove();
+ for (var i = 0; i < tags.length; i++) {
+ var newtag = $('<li><a href="#" class="token_tag"></a></li>');
+ newtag.find('a').text(tags[i]);
+ newtag.addClass(tagclass);
+ container.append(newtag);
+ this.cxt_suggested_available++;
+ }
+ };
+ this.fillUserTags = function() {
+ thePKT_SAVED.sendMessage("getTags", {}, function(resp)
+ {
+ if (typeof resp == 'object' && typeof resp.tags == 'object')
+ {
+ myself.userTags = resp.tags;
+ }
+ });
+ };
+ this.fillSuggestedTags = function()
+ {
+ if (!$('.pkt_ext_suggestedtag_detail').length)
+ {
+ myself.suggestedTagsLoaded = true;
+ myself.startCloseTimer();
+ return;
+ }
+
+ thePKT_SAVED.sendMessage("getSuggestedTags",
+ {
+ url: myself.savedUrl
+ }, function(resp)
+ {
+ $('.pkt_ext_suggestedtag_detail').removeClass('pkt_ext_suggestedtag_detail_loading');
+ if (resp.status == 'success')
+ {
+ var newtags = [];
+ for (var i = 0; i < resp.value.suggestedTags.length; i++)
+ {
+ newtags.push(resp.value.suggestedTags[i].tag);
+ }
+ myself.suggestedTagsLoaded = true;
+ if (!myself.mouseInside) {
+ myself.startCloseTimer();
+ }
+ myself.fillTagContainer(newtags, $('.pkt_ext_suggestedtag_detail ul'), 'token_suggestedtag');
+ }
+ else if (resp.status == 'error') {
+ var msg = $('<p class="suggestedtag_msg">');
+ msg.text(resp.error.message);
+ $('.pkt_ext_suggestedtag_detail').append(msg);
+ this.suggestedTagsLoaded = true;
+ if (!myself.mouseInside) {
+ myself.startCloseTimer();
+ }
+ }
+ });
+ }
+ this.initAutoCloseEvents = function() {
+ this.wrapper.on('mouseenter', function() {
+ myself.mouseInside = true;
+ myself.stopCloseTimer();
+ });
+ this.wrapper.on('mouseleave', function() {
+ myself.mouseInside = false;
+ myself.startCloseTimer();
+ });
+ this.wrapper.on('click', function(e) {
+ myself.closeValid = false;
+ });
+ };
+ this.startCloseTimer = function(manualtime)
+ {
+ var settime = manualtime ? manualtime : myself.autocloseTiming;
+ if (typeof myself.autocloseTimer == 'number')
+ {
+ clearTimeout(myself.autocloseTimer);
+ }
+ myself.autocloseTimer = setTimeout(function()
+ {
+ if (myself.closeValid || myself.preventCloseTimerCancel)
+ {
+ myself.preventCloseTimerCancel = false;
+ myself.closePopup();
+ }
+ }, settime);
+ };
+ this.stopCloseTimer = function()
+ {
+ if (myself.preventCloseTimerCancel)
+ {
+ return;
+ }
+ clearTimeout(myself.autocloseTimer);
+ };
+ this.closePopup = function() {
+ myself.stopCloseTimer();
+ thePKT_SAVED.sendMessage("close");
+ };
+ this.checkValidTagSubmit = function() {
+ var inputlength = $.trim($('.pkt_ext_tag_input_wrapper').find('.token-input-input-token').children('input').val()).length;
+ if ($('.pkt_ext_containersaved').find('.token-input-token').length || (inputlength > 0 && inputlength < 26))
+ {
+ $('.pkt_ext_containersaved').find('.pkt_ext_btn').removeClass('pkt_ext_btn_disabled');
+ }
+ else
+ {
+ $('.pkt_ext_containersaved').find('.pkt_ext_btn').addClass('pkt_ext_btn_disabled');
+ }
+ myself.updateSlidingTagList();
+ };
+ this.updateSlidingTagList = function() {
+ var inputleft = $('.token-input-input-token input').position().left;
+ var listleft = $('.token-input-list').position().left;
+ var listleftmanual = parseInt($('.token-input-list').css('left'));
+ var listleftnatural = listleft - listleftmanual;
+ var leftwidth = $('.pkt_ext_tag_input_wrapper').outerWidth();
+
+ if ((inputleft + listleft + 20) > leftwidth)
+ {
+ $('.token-input-list').css('left', Math.min(((inputleft + listleftnatural - leftwidth + 20)*-1), 0) + 'px');
+ }
+ else
+ {
+ $('.token-input-list').css('left', '0');
+ }
+ };
+ this.checkPlaceholderStatus = function() {
+ if (this.wrapper.find('.pkt_ext_tag_input_wrapper').find('.token-input-token').length)
+ {
+ this.wrapper.find('.token-input-input-token input').attr('placeholder', '');
+ }
+ else
+ {
+ this.wrapper.find('.token-input-input-token input').attr('placeholder', $('.pkt_ext_tag_input').attr('placeholder')).css('width', '200px');
+ }
+ };
+ this.initTagInput = function() {
+ var inputwrapper = $('.pkt_ext_tag_input_wrapper');
+ inputwrapper.find('.pkt_ext_tag_input').tokenInput([], {
+ searchDelay: 200,
+ minChars: 1,
+ animateDropdown: false,
+ noResultsHideDropdown: true,
+ scrollKeyboard: true,
+ emptyInputLength: 200,
+ search_function: function(term, cb) {
+ var returnlist = [];
+ if (term.length) {
+ var limit = 15;
+ var r = new RegExp('^' + term);
+ for (var i = 0; i < myself.userTags.length; i++) {
+ if (r.test(myself.userTags[i]) && limit > 0) {
+ returnlist.push({name:myself.userTags[i]});
+ limit--;
+ }
+ }
+ }
+ if (!$('.token-input-dropdown-tag').data('init')) {
+ $('.token-input-dropdown-tag').css('width', inputwrapper.outerWidth()).data('init');
+ inputwrapper.append($('.token-input-dropdown-tag'));
+ }
+ cb(returnlist);
+ },
+ textToData: function(text) {
+ if ($.trim(text).length > 25 || !$.trim(text).length) {
+ if (text.length > 25) {
+ myself.showTagsError(myself.dictJSON.maxtaglength);
+ changestamp = Date.now();
+ setTimeout(function() {
+ $('.token-input-input-token input').val(text).focus();
+ }, 10);
+ }
+ return null;
+ }
+ myself.hideTagsError();
+ return {name:myself.sanitizeText(text.toLowerCase())};
+ },
+ onReady: function() {
+ $('.token-input-dropdown').addClass('token-input-dropdown-tag');
+ inputwrapper.find('.token-input-input-token input').attr('placeholder', $('.tag-input').attr('placeholder')).css('width', '200px');
+ if ($('.pkt_ext_suggestedtag_detail').length) {
+ myself.wrapper.find('.pkt_ext_suggestedtag_detail').on('click', '.token_tag', function(e) {
+ e.preventDefault();
+ var tag = $(e.target);
+ if ($(this).parents('.pkt_ext_suggestedtag_detail_disabled').length) {
+ return;
+ }
+ myself.justaddedsuggested = true;
+ inputwrapper.find('.pkt_ext_tag_input').tokenInput('add', {id:inputwrapper.find('.token-input-token').length, name:tag.text()});
+ tag.addClass('token-suggestedtag-inactive');
+ $('.token-input-input-token input').focus();
+ });
+ }
+ $('.token-input-list').on('keydown', 'input', function(e) {
+ if (e.which == 37) {
+ myself.updateSlidingTagList();
+ }
+ }).on('keypress', 'input', function(e) {
+ if (e.which == 13) {
+ if (typeof changestamp == 'undefined' || (Date.now() - changestamp > 250)) {
+ e.preventDefault();
+ myself.wrapper.find('.pkt_ext_btn').trigger('click');
+ }
+ }
+ }).on('keyup', 'input', function(e) {
+ myself.checkValidTagSubmit();
+ });
+ myself.checkPlaceholderStatus();
+ },
+ onAdd: function() {
+ myself.checkValidTagSubmit();
+ changestamp = Date.now();
+ myself.hideInactiveTags();
+ myself.checkPlaceholderStatus();
+ },
+ onDelete: function() {
+ myself.checkValidTagSubmit();
+ changestamp = Date.now();
+ myself.showActiveTags();
+ myself.checkPlaceholderStatus();
+ },
+ onShowDropdown: function() {
+ thePKT_SAVED.sendMessage("expandSavePanel");
+ },
+ onHideDropdown: function() {
+ thePKT_SAVED.sendMessage("collapseSavePanel");
+ }
+ });
+ $('body').on('keydown', function(e) {
+ var key = e.keyCode || e.which;
+ if (key == 8) {
+ var selected = $('.token-input-selected-token');
+ if (selected.length) {
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ inputwrapper.find('.pkt_ext_tag_input').tokenInput('remove', {name:selected.find('p').text()});
+ }
+ }
+ else if ($(e.target).parent().hasClass('token-input-input-token')) {
+ e.stopImmediatePropagation();
+ }
+ });
+ };
+ this.disableInput = function() {
+ this.wrapper.find('.pkt_ext_item_actions').addClass('pkt_ext_item_actions_disabled');
+ this.wrapper.find('.pkt_ext_btn').addClass('pkt_ext_btn_disabled');
+ this.wrapper.find('.pkt_ext_tag_input_wrapper').addClass('pkt_ext_tag_input_wrapper_disabled');
+ if (this.wrapper.find('.pkt_ext_suggestedtag_detail').length) {
+ this.wrapper.find('.pkt_ext_suggestedtag_detail').addClass('pkt_ext_suggestedtag_detail_disabled');
+ }
+ };
+ this.enableInput = function() {
+ this.wrapper.find('.pkt_ext_item_actions').removeClass('pkt_ext_item_actions_disabled');
+ this.checkValidTagSubmit();
+ this.wrapper.find('.pkt_ext_tag_input_wrapper').removeClass('pkt_ext_tag_input_wrapper_disabled');
+ if (this.wrapper.find('.pkt_ext_suggestedtag_detail').length) {
+ this.wrapper.find('.pkt_ext_suggestedtag_detail').removeClass('pkt_ext_suggestedtag_detail_disabled');
+ }
+ };
+ this.initAddTagInput = function() {
+ $('.pkt_ext_btn').click(function(e) {
+ e.preventDefault();
+ if ($(this).hasClass('pkt_ext_btn_disabled') || $('.pkt_ext_edit_msg_active').filter('.pkt_ext_edit_msg_error').length)
+ {
+ return;
+ }
+ myself.disableInput();
+ $('.pkt_ext_containersaved').find('.pkt_ext_detail h2').text(myself.dictJSON.processingtags);
+ var originaltags = [];
+ $('.token-input-token').each(function()
+ {
+ var text = $.trim($(this).find('p').text());
+ if (text.length)
+ {
+ originaltags.push(text);
+ }
+ });
+
+ thePKT_SAVED.sendMessage("addTags",
+ {
+ url: myself.savedUrl,
+ tags: originaltags
+ }, function(resp)
+ {
+ if (resp.status == 'success')
+ {
+ myself.showStateFinalMsg(myself.dictJSON.tagssaved);
+ }
+ else if (resp.status == 'error')
+ {
+ $('.pkt_ext_edit_msg').addClass('pkt_ext_edit_msg_error pkt_ext_edit_msg_active').text(resp.error.message);
+ }
+ });
+ });
+ };
+ this.initRemovePageInput = function() {
+ $('.pkt_ext_removeitem').click(function(e) {
+ if ($(this).parents('.pkt_ext_item_actions_disabled').length) {
+ e.preventDefault();
+ return;
+ }
+ if ($(this).hasClass('pkt_ext_removeitem')) {
+ e.preventDefault();
+ myself.disableInput();
+ $('.pkt_ext_containersaved').find('.pkt_ext_detail h2').text(myself.dictJSON.processingremove);
+
+ thePKT_SAVED.sendMessage("deleteItem",
+ {
+ itemId: myself.savedItemId
+ }, function(resp) {
+ if (resp.status == 'success') {
+ myself.showStateFinalMsg(myself.dictJSON.pageremoved);
+ }
+ else if (resp.status == 'error') {
+ $('.pkt_ext_edit_msg').addClass('pkt_ext_edit_msg_error pkt_ext_edit_msg_active').text(resp.error.message);
+ }
+ });
+ }
+ });
+ };
+ this.initOpenListInput = function() {
+ $('.pkt_ext_openpocket').click(function(e)
+ {
+ e.preventDefault();
+ thePKT_SAVED.sendMessage("openTabWithUrl",
+ {
+ url: $(this).attr('href'),
+ activate: true
+ });
+ myself.closePopup();
+ });
+ };
+ this.showTagsError = function(msg) {
+ $('.pkt_ext_edit_msg').addClass('pkt_ext_edit_msg_error pkt_ext_edit_msg_active').text(msg);
+ $('.pkt_ext_tag_detail').addClass('pkt_ext_tag_error');
+ };
+ this.hideTagsError = function(msg) {
+ $('.pkt_ext_edit_msg').removeClass('pkt_ext_edit_msg_error pkt_ext_edit_msg_active').text('');
+ $('.pkt_ext_tag_detail').removeClass('pkt_ext_tag_error');
+ };
+ this.showActiveTags = function() {
+ if (!$('.pkt_ext_suggestedtag_detail').length) {
+ return;
+ }
+ var activetokenstext = '|';
+ $('.token-input-token').each(function(index, element) {
+ activetokenstext += $(element).find('p').text() + '|';
+ });
+
+ var inactivetags = $('.pkt_ext_suggestedtag_detail').find('.token_tag_inactive');
+ inactivetags.each(function(index, element) {
+ if (activetokenstext.indexOf('|' + $(element).text() + '|') == -1) {
+ $(element).removeClass('token_tag_inactive');
+ }
+ });
+ };
+ this.hideInactiveTags = function() {
+ if (!$('.pkt_ext_suggestedtag_detail').length) {
+ return;
+ }
+ var activetokenstext = '|';
+ $('.token-input-token').each(function(index, element) {
+ activetokenstext += $(element).find('p').text() + '|';
+ });
+ var activesuggestedtags = $('.token_tag').not('.token_tag_inactive');
+ activesuggestedtags.each(function(index, element) {
+ if (activetokenstext.indexOf('|' + $(element).text() + '|') > -1) {
+ $(element).addClass('token_tag_inactive');
+ }
+ });
+ };
+ this.showStateSaved = function(initobj) {
+ this.wrapper.find('.pkt_ext_detail h2').text(this.dictJSON.pagesaved);
+ this.wrapper.find('.pkt_ext_btn').addClass('pkt_ext_btn_disabled');
+ if (typeof initobj.item == 'object')
+ {
+ this.savedItemId = initobj.item.item_id;
+ this.savedUrl = initobj.item.given_url;
+ }
+ $('.pkt_ext_containersaved').addClass('pkt_ext_container_detailactive').removeClass('pkt_ext_container_finalstate');
+
+ myself.fillUserTags();
+ if (myself.suggestedTagsLoaded) {
+ myself.startCloseTimer();
+ }
+ else {
+ myself.fillSuggestedTags();
+ }
+ };
+ this.sanitizeText = function(s) {
+ var sanitizeMap = {
+ "&": "&amp;",
+ "<": "&lt;",
+ ">": "&gt;",
+ '"': '&quot;',
+ "'": '&#39;'
+ };
+ if (typeof s !== 'string')
+ {
+ return '';
+ }
+ return String(s).replace(/[&<>"']/g, function (str) {
+ return sanitizeMap[str];
+ });
+ };
+ this.showStateFinalMsg = function(msg) {
+ this.wrapper.find('.pkt_ext_tag_detail').one('webkitTransitionEnd transitionend msTransitionEnd oTransitionEnd', function(e)
+ {
+ $(this).off('webkitTransitionEnd transitionend msTransitionEnd oTransitionEnd');
+ myself.preventCloseTimerCancel = true;
+ myself.startCloseTimer(myself.autocloseTimingFinalState);
+ myself.wrapper.find('.pkt_ext_detail h2').text(msg);
+ });
+ this.wrapper.addClass('pkt_ext_container_finalstate');
+ };
+ this.showStateError = function(headline, detail) {
+ this.wrapper.find('.pkt_ext_detail h2').text(headline);
+ this.wrapper.find('.pkt_ext_detail h3').text(detail);
+ this.wrapper.addClass('pkt_ext_container_detailactive pkt_ext_container_finalstate pkt_ext_container_finalerrorstate');
+ this.preventCloseTimerCancel = true;
+ this.startCloseTimer(myself.autocloseTimingFinalState);
+ }
+ this.getTranslations = function()
+ {
+ this.dictJSON = window.pocketStrings;
+ };
+};
+
+PKT_SAVED_OVERLAY.prototype = {
+ create : function()
+ {
+ if (this.active)
+ {
+ return;
+ }
+ this.active = true;
+
+ // set translations
+ this.getTranslations();
+
+ // set host
+ this.dictJSON.pockethost = this.pockethost;
+
+ // extra modifier class for collapsed state
+ if (this.inoverflowmenu)
+ {
+ $('body').addClass('pkt_ext_saved_overflow');
+ }
+
+ // extra modifier class for language
+ if (this.locale)
+ {
+ $('body').addClass('pkt_ext_saved_' + this.locale);
+ }
+
+ // Create actual content
+ $('body').append(Handlebars.templates.saved_shell(this.dictJSON));
+
+ // Add in premium content (if applicable based on premium status)
+ this.createPremiumFunctionality();
+
+ // Initialize functionality for overlay
+ this.wrapper = $('.pkt_ext_containersaved');
+ this.initTagInput();
+ this.initAddTagInput();
+ this.initRemovePageInput();
+ this.initOpenListInput();
+ this.initAutoCloseEvents();
+ },
+ createPremiumFunctionality: function()
+ {
+ if (this.premiumStatus && !$('.pkt_ext_suggestedtag_detail').length)
+ {
+ $('body').append(Handlebars.templates.saved_premiumshell(this.dictJSON));
+ $('.pkt_ext_initload').append(Handlebars.templates.saved_premiumextras(this.dictJSON));
+ }
+ }
+};
+
+
+// Layer between Bookmarklet and Extensions
+var PKT_SAVED = function () {};
+
+PKT_SAVED.prototype = {
+ init: function () {
+ if (this.inited) {
+ return;
+ }
+ this.panelId = pktPanelMessaging.panelIdFromURL(window.location.href);
+ this.overlay = new PKT_SAVED_OVERLAY();
+
+ this.inited = true;
+ },
+
+ addMessageListener: function(messageId, callback) {
+ pktPanelMessaging.addMessageListener(this.panelId, messageId, callback);
+ },
+
+ sendMessage: function(messageId, payload, callback) {
+ pktPanelMessaging.sendMessage(this.panelId, messageId, payload, callback);
+ },
+
+ create: function() {
+ var myself = this;
+ var url = window.location.href.match(/premiumStatus=([\w|\d|\.]*)&?/);
+ if (url && url.length > 1)
+ {
+ myself.overlay.premiumStatus = (url[1] == '1');
+ }
+ var host = window.location.href.match(/pockethost=([\w|\.]*)&?/);
+ if (host && host.length > 1)
+ {
+ myself.overlay.pockethost = host[1];
+ }
+ var inoverflowmenu = window.location.href.match(/inoverflowmenu=([\w|\.]*)&?/);
+ if (inoverflowmenu && inoverflowmenu.length > 1)
+ {
+ myself.overlay.inoverflowmenu = (inoverflowmenu[1] == 'true');
+ }
+ var locale = window.location.href.match(/locale=([\w|\.]*)&?/);
+ if (locale && locale.length > 1)
+ {
+ myself.overlay.locale = locale[1].toLowerCase();
+ }
+
+ myself.overlay.create();
+
+ // tell back end we're ready
+ thePKT_SAVED.sendMessage("show");
+
+ // wait confirmation of save before flipping to final saved state
+ thePKT_SAVED.addMessageListener("saveLink", function(resp)
+ {
+ if (resp.status == 'error') {
+ if (typeof resp.error == 'object')
+ {
+ if (resp.error.localizedKey)
+ {
+ myself.overlay.showStateError(myself.overlay.dictJSON.pagenotsaved, myself.overlay.dictJSON[resp.error.localizedKey]);
+ }
+ else
+ {
+ myself.overlay.showStateError(myself.overlay.dictJSON.pagenotsaved, resp.error.message);
+ }
+ }
+ else
+ {
+ myself.overlay.showStateError(myself.overlay.dictJSON.pagenotsaved, myself.overlay.dictJSON.errorgeneric);
+ }
+ return;
+ }
+
+ myself.overlay.showStateSaved(resp);
+ });
+
+ }
+}
+
+$(function()
+{
+ if (!window.thePKT_SAVED) {
+ var thePKT_SAVED = new PKT_SAVED();
+ window.thePKT_SAVED = thePKT_SAVED;
+ thePKT_SAVED.init();
+ }
+
+ var pocketHost = thePKT_SAVED.overlay.pockethost;
+ // send an async message to get string data
+ thePKT_SAVED.sendMessage("initL10N", {
+ tos: [
+ 'https://'+ pocketHost +'/tos?s=ffi&t=tos&tv=panel_tryit',
+ 'https://'+ pocketHost +'/privacy?s=ffi&t=privacypolicy&tv=panel_tryit'
+ ]
+ }, function(resp) {
+ window.pocketStrings = resp.strings;
+ window.thePKT_SAVED.create();
+ });
+});
diff --git a/browser/extensions/pocket/content/panels/js/signup.js b/browser/extensions/pocket/content/panels/js/signup.js
new file mode 100644
index 000000000..af55cc2a7
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/js/signup.js
@@ -0,0 +1,193 @@
+/*
+PKT_SIGNUP_OVERLAY is the view itself and contains all of the methods to manipute the overlay and messaging.
+It does not contain any logic for saving or communication with the extension or server.
+*/
+var PKT_SIGNUP_OVERLAY = function (options)
+{
+ var myself = this;
+ this.inited = false;
+ this.active = false;
+ this.delayedStateSaved = false;
+ this.wrapper = null;
+ this.variant = window.___PKT__SIGNUP_VARIANT;
+ this.tagline = window.___PKT__SIGNUP_TAGLINE || '';
+ this.preventCloseTimerCancel = false;
+ this.translations = {};
+ this.closeValid = true;
+ this.mouseInside = false;
+ this.autocloseTimer = null;
+ this.variant = "";
+ this.inoverflowmenu = false;
+ this.controlvariant;
+ this.pockethost = "getpocket.com";
+ this.fxasignedin = false;
+ this.dictJSON = {};
+ this.initCloseTabEvents = function() {
+ $('.btn,.pkt_ext_learnmore,.alreadyhave > a').click(function(e)
+ {
+ e.preventDefault();
+ thePKT_SIGNUP.sendMessage("openTabWithUrl",
+ {
+ url: $(this).attr('href'),
+ activate: true
+ });
+ myself.closePopup();
+ });
+ };
+ this.closePopup = function() {
+ thePKT_SIGNUP.sendMessage("close");
+ };
+ this.sanitizeText = function(s) {
+ var sanitizeMap = {
+ "&": "&amp;",
+ "<": "&lt;",
+ ">": "&gt;",
+ '"': '&quot;',
+ "'": '&#39;'
+ };
+ if (typeof s !== 'string')
+ {
+ return '';
+ }
+ return String(s).replace(/[&<>"']/g, function (str) {
+ return sanitizeMap[str];
+ });
+ };
+ this.getTranslations = function()
+ {
+ this.dictJSON = window.pocketStrings;
+ };
+
+};
+
+PKT_SIGNUP_OVERLAY.prototype = {
+ create : function()
+ {
+ var controlvariant = window.location.href.match(/controlvariant=([\w|\.]*)&?/);
+ if (controlvariant && controlvariant.length > 1)
+ {
+ this.controlvariant = controlvariant[1];
+ }
+ var variant = window.location.href.match(/variant=([\w|\.]*)&?/);
+ if (variant && variant.length > 1)
+ {
+ this.variant = variant[1];
+ }
+ var fxasignedin = window.location.href.match(/fxasignedin=([\w|\d|\.]*)&?/);
+ if (fxasignedin && fxasignedin.length > 1)
+ {
+ this.fxasignedin = (fxasignedin[1] == '1');
+ }
+ var host = window.location.href.match(/pockethost=([\w|\.]*)&?/);
+ if (host && host.length > 1)
+ {
+ this.pockethost = host[1];
+ }
+ var inoverflowmenu = window.location.href.match(/inoverflowmenu=([\w|\.]*)&?/);
+ if (inoverflowmenu && inoverflowmenu.length > 1)
+ {
+ this.inoverflowmenu = (inoverflowmenu[1] == 'true');
+ }
+ var locale = window.location.href.match(/locale=([\w|\.]*)&?/);
+ if (locale && locale.length > 1)
+ {
+ this.locale = locale[1].toLowerCase();
+ }
+
+ if (this.active)
+ {
+ return;
+ }
+ this.active = true;
+
+ // set translations
+ this.getTranslations();
+ this.dictJSON.fxasignedin = this.fxasignedin ? 1 : 0;
+ this.dictJSON.controlvariant = this.controlvariant == 'true' ? 1 : 0;
+ this.dictJSON.variant = (this.variant ? this.variant : 'undefined');
+ this.dictJSON.variant += this.fxasignedin ? '_fxa' : '_nonfxa';
+ this.dictJSON.pockethost = this.pockethost;
+ this.dictJSON.showlearnmore = true;
+
+ // extra modifier class for collapsed state
+ if (this.inoverflowmenu)
+ {
+ $('body').addClass('pkt_ext_signup_overflow');
+ }
+
+ // extra modifier class for language
+ if (this.locale)
+ {
+ $('body').addClass('pkt_ext_signup_' + this.locale);
+ }
+
+ // Create actual content
+ if (this.variant == 'overflow')
+ {
+ $('body').append(Handlebars.templates.signup_shell(this.dictJSON));
+ }
+ else
+ {
+ $('body').append(Handlebars.templates.signupstoryboard_shell(this.dictJSON));
+ }
+
+
+ // tell background we're ready
+ thePKT_SIGNUP.sendMessage("show");
+
+ // close events
+ this.initCloseTabEvents();
+ }
+};
+
+
+// Layer between Bookmarklet and Extensions
+var PKT_SIGNUP = function () {};
+
+PKT_SIGNUP.prototype = {
+ init: function () {
+ if (this.inited) {
+ return;
+ }
+ this.panelId = pktPanelMessaging.panelIdFromURL(window.location.href);
+ this.overlay = new PKT_SIGNUP_OVERLAY();
+
+ this.inited = true;
+ },
+
+ addMessageListener: function(messageId, callback) {
+ pktPanelMessaging.addMessageListener(this.panelId, messageId, callback);
+ },
+
+ sendMessage: function(messageId, payload, callback) {
+ pktPanelMessaging.sendMessage(this.panelId, messageId, payload, callback);
+ },
+
+ create: function() {
+ this.overlay.create();
+
+ // tell back end we're ready
+ thePKT_SIGNUP.sendMessage("show");
+ }
+}
+
+$(function()
+{
+ if (!window.thePKT_SIGNUP) {
+ var thePKT_SIGNUP = new PKT_SIGNUP();
+ window.thePKT_SIGNUP = thePKT_SIGNUP;
+ thePKT_SIGNUP.init();
+ }
+
+ var pocketHost = thePKT_SIGNUP.overlay.pockethost;
+ // send an async message to get string data
+ thePKT_SIGNUP.sendMessage("initL10N", {
+ tos: [
+ 'https://'+ pocketHost +'/tos?s=ffi&t=tos&tv=panel_tryit',
+ 'https://'+ pocketHost +'/privacy?s=ffi&t=privacypolicy&tv=panel_tryit'
+ ]
+ }, function(resp) {
+ window.pocketStrings = resp.strings;
+ window.thePKT_SIGNUP.create();
+ });
+});
diff --git a/browser/extensions/pocket/content/panels/js/tmpl.js b/browser/extensions/pocket/content/panels/js/tmpl.js
new file mode 100644
index 000000000..a03ffda70
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/js/tmpl.js
@@ -0,0 +1,242 @@
+(function() {
+ var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
+templates['saved_premiumextras'] = template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
+ return "<div class=\"pkt_ext_suggestedtag_detailshown\">\r\n</div> ";
+ },"useData":true});
+templates['saved_premiumshell'] = template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
+ var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
+ return "<div class=\"pkt_ext_suggestedtag_detail pkt_ext_suggestedtag_detail_loading\">\n <h4>"
+ + escapeExpression(((helper = (helper = helpers.suggestedtags || (depth0 != null ? depth0.suggestedtags : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"suggestedtags","hash":{},"data":data}) : helper)))
+ + "</h4>\n <div class=\"pkt_ext_loadingspinner\"><div></div></div>\n <ul class=\"pkt_ext_cf\">\n </ul>\n</div>";
+},"useData":true});
+templates['saved_shell'] = template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
+ var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
+ return "<div class=\"pkt_ext_initload\">\n <div class=\"pkt_ext_logo\"></div> \n <div class=\"pkt_ext_topdetail\">\n <h2>"
+ + escapeExpression(((helper = (helper = helpers.saving || (depth0 != null ? depth0.saving : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"saving","hash":{},"data":data}) : helper)))
+ + "</h2>\n </div> \n <div class=\"pkt_ext_loadingspinner\"><div></div></div>\n</div> \n<div class=\"pkt_ext_detail\"> \n <div class=\"pkt_ext_logo\"></div>\n <div class=\"pkt_ext_topdetail\">\n <h2>"
+ + escapeExpression(((helper = (helper = helpers.pagesaved || (depth0 != null ? depth0.pagesaved : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pagesaved","hash":{},"data":data}) : helper)))
+ + "</h2>\n <h3 class=\"pkt_ext_errordetail\"></h3>\n <nav class=\"pkt_ext_item_actions pkt_ext_cf\">\n <ul>\n <li><a class=\"pkt_ext_removeitem\" href=\"#\">"
+ + escapeExpression(((helper = (helper = helpers.removepage || (depth0 != null ? depth0.removepage : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"removepage","hash":{},"data":data}) : helper)))
+ + "</a></li>\n <li class=\"pkt_ext_actions_separator\"></li> \n <li><a class=\"pkt_ext_openpocket\" href=\"https://"
+ + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper)))
+ + "/a?src=ff_ext_saved\" target=\"_blank\">"
+ + escapeExpression(((helper = (helper = helpers.viewlist || (depth0 != null ? depth0.viewlist : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"viewlist","hash":{},"data":data}) : helper)))
+ + "</a></li>\n </ul>\n </nav> \n </div>\n <div class=\"pkt_ext_tag_detail pkt_ext_cf\">\n <div class=\"pkt_ext_tag_input_wrapper\">\n <div class=\"pkt_ext_tag_input_blocker\"></div>\n <input class=\"pkt_ext_tag_input\" type=\"text\" placeholder=\""
+ + escapeExpression(((helper = (helper = helpers.addtags || (depth0 != null ? depth0.addtags : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"addtags","hash":{},"data":data}) : helper)))
+ + "\">\n </div>\n <a href=\"#\" class=\"pkt_ext_btn pkt_ext_btn_disabled\">"
+ + escapeExpression(((helper = (helper = helpers.save || (depth0 != null ? depth0.save : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"save","hash":{},"data":data}) : helper)))
+ + "</a>\n </div>\n <p class=\"pkt_ext_edit_msg\"></p>\n</div>";
+},"useData":true});
+templates['signup_shell'] = template({"1":function(depth0,helpers,partials,data) {
+ var stack1, buffer = "";
+ stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.controlvariant : depth0), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.program(4, data),"data":data});
+ if (stack1 != null) { buffer += stack1; }
+ return buffer;
+},"2":function(depth0,helpers,partials,data) {
+ var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
+ return " <p class=\"pkt_ext_learnmorecontainer\"><a class=\"pkt_ext_learnmore\" href=\"https://"
+ + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper)))
+ + "/firefox_learnmore?s=ffi&t=learnmore&tv=panel_control&v="
+ + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper)))
+ + "\" target=\"_blank\">"
+ + escapeExpression(((helper = (helper = helpers.learnmore || (depth0 != null ? depth0.learnmore : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"learnmore","hash":{},"data":data}) : helper)))
+ + "</a></p>\n";
+},"4":function(depth0,helpers,partials,data) {
+ var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
+ return " <p class=\"pkt_ext_learnmorecontainer\"><a class=\"pkt_ext_learnmore\" href=\"https://"
+ + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper)))
+ + "/firefox_learnmore?s=ffi&t=learnmore&tv=panel_tryit&v="
+ + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper)))
+ + "\" target=\"_blank\">"
+ + escapeExpression(((helper = (helper = helpers.learnmore || (depth0 != null ? depth0.learnmore : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"learnmore","hash":{},"data":data}) : helper)))
+ + "</a></p>\n";
+},"6":function(depth0,helpers,partials,data) {
+ var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
+ return " <p class=\"pkt_ext_learnmorecontainer\"><a class=\"pkt_ext_learnmore pkt_ext_learnmoreinactive\" href=\"#\">"
+ + escapeExpression(((helper = (helper = helpers.learnmore || (depth0 != null ? depth0.learnmore : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"learnmore","hash":{},"data":data}) : helper)))
+ + "</a></p>\n";
+},"8":function(depth0,helpers,partials,data) {
+ var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
+ return " <h4>"
+ + escapeExpression(((helper = (helper = helpers.signuptosave || (depth0 != null ? depth0.signuptosave : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"signuptosave","hash":{},"data":data}) : helper)))
+ + "</h4>\n <p class=\"btn-container\"><a href=\"https://"
+ + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper)))
+ + "/ff_signup?s=ffi&t=signupff&v="
+ + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper)))
+ + "\" target=\"_blank\" class=\"btn signup-btn-firefox\"><span class=\"logo\"></span><span class=\"text\">"
+ + escapeExpression(((helper = (helper = helpers.signinfirefox || (depth0 != null ? depth0.signinfirefox : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"signinfirefox","hash":{},"data":data}) : helper)))
+ + "</span></a></p>\n <p class=\"alreadyhave\">"
+ + escapeExpression(((helper = (helper = helpers.alreadyhaveacct || (depth0 != null ? depth0.alreadyhaveacct : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"alreadyhaveacct","hash":{},"data":data}) : helper)))
+ + " <a href=\"https://"
+ + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper)))
+ + "/login?ep=3&src=extension&s=ffi&t=login&v="
+ + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper)))
+ + "\" target=\"_blank\">"
+ + escapeExpression(((helper = (helper = helpers.loginnow || (depth0 != null ? depth0.loginnow : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"loginnow","hash":{},"data":data}) : helper)))
+ + "</a>.</p>\n";
+},"10":function(depth0,helpers,partials,data) {
+ var stack1, buffer = "";
+ stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.controlvariant : depth0), {"name":"if","hash":{},"fn":this.program(11, data),"inverse":this.program(13, data),"data":data});
+ if (stack1 != null) { buffer += stack1; }
+ return buffer;
+},"11":function(depth0,helpers,partials,data) {
+ var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
+ return " <h4>"
+ + escapeExpression(((helper = (helper = helpers.signuptosave || (depth0 != null ? depth0.signuptosave : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"signuptosave","hash":{},"data":data}) : helper)))
+ + "</h4>\n <p class=\"btn-container\"><a href=\"https://"
+ + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper)))
+ + "/ff_signup?s=ffi&tv=panel_control&t=signupff&v="
+ + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper)))
+ + "\" target=\"_blank\" class=\"btn signup-btn-firefox\"><span class=\"logo\"></span><span class=\"text\">"
+ + escapeExpression(((helper = (helper = helpers.signupfirefox || (depth0 != null ? depth0.signupfirefox : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"signupfirefox","hash":{},"data":data}) : helper)))
+ + "</span></a></p>\n <p class=\"btn-container\"><a href=\"https://"
+ + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper)))
+ + "/signup?force=email&tv=panel_control&src=extension&s=ffi&t=signupemail&v="
+ + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper)))
+ + "\" target=\"_blank\" class=\"btn btn-secondary signup-btn-email signup-btn-initstate\">"
+ + escapeExpression(((helper = (helper = helpers.signupemail || (depth0 != null ? depth0.signupemail : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"signupemail","hash":{},"data":data}) : helper)))
+ + "</a></p>\n <p class=\"alreadyhave\">"
+ + escapeExpression(((helper = (helper = helpers.alreadyhaveacct || (depth0 != null ? depth0.alreadyhaveacct : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"alreadyhaveacct","hash":{},"data":data}) : helper)))
+ + " <a href=\"https://"
+ + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper)))
+ + "/login?ep=3&tv=panel_control&src=extension&s=ffi&t=login&v="
+ + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper)))
+ + "\" target=\"_blank\">"
+ + escapeExpression(((helper = (helper = helpers.loginnow || (depth0 != null ? depth0.loginnow : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"loginnow","hash":{},"data":data}) : helper)))
+ + "</a>.</p>\n";
+},"13":function(depth0,helpers,partials,data) {
+ var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = " <p class=\"btn-container\"><a href=\"https://"
+ + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper)))
+ + "/firefox_tryitnow?s=ffi&tv=panel_tryit&t=tryitnow\" target=\"_blank\" class=\"btn signup-btn-tryitnow\"><span class=\"text\">"
+ + escapeExpression(((helper = (helper = helpers.tryitnow || (depth0 != null ? depth0.tryitnow : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"tryitnow","hash":{},"data":data}) : helper)))
+ + "</span></a></p>\n <p class=\"alreadyhave tryitnowspace\">"
+ + escapeExpression(((helper = (helper = helpers.alreadyhaveacct || (depth0 != null ? depth0.alreadyhaveacct : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"alreadyhaveacct","hash":{},"data":data}) : helper)))
+ + " <a href=\"https://"
+ + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper)))
+ + "/login?ep=3&s=ffi&tv=panel_tryit&src=extension&t=login&v="
+ + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper)))
+ + "\" target=\"_blank\">"
+ + escapeExpression(((helper = (helper = helpers.loginnow || (depth0 != null ? depth0.loginnow : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"loginnow","hash":{},"data":data}) : helper)))
+ + "</a>.</p>\n <p class=\"pkt_ext_tos\">";
+ stack1 = ((helper = (helper = helpers.tos || (depth0 != null ? depth0.tos : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"tos","hash":{},"data":data}) : helper));
+ if (stack1 != null) { buffer += stack1; }
+ return buffer + "</p>\n";
+},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
+ var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "<div class=\"pkt_ext_introdetail pkt_ext_introdetailhero\">\n <h2 class=\"pkt_ext_logo\">Pocket</h2>\n <p class=\"pkt_ext_tagline\">"
+ + escapeExpression(((helper = (helper = helpers.tagline || (depth0 != null ? depth0.tagline : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"tagline","hash":{},"data":data}) : helper)))
+ + "</p>\n";
+ stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.showlearnmore : depth0), {"name":"if","hash":{},"fn":this.program(1, data),"inverse":this.program(6, data),"data":data});
+ if (stack1 != null) { buffer += stack1; }
+ buffer += " <div class=\"pkt_ext_introimg\"></div>\n</div>\n<div class=\"pkt_ext_signupdetail pkt_ext_signupdetail_hero\">\n";
+ stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.fxasignedin : depth0), {"name":"if","hash":{},"fn":this.program(8, data),"inverse":this.program(10, data),"data":data});
+ if (stack1 != null) { buffer += stack1; }
+ return buffer + "</div>\n";
+},"useData":true});
+templates['signupstoryboard_shell'] = template({"1":function(depth0,helpers,partials,data) {
+ var stack1, buffer = "";
+ stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.controlvariant : depth0), {"name":"if","hash":{},"fn":this.program(2, data),"inverse":this.program(4, data),"data":data});
+ if (stack1 != null) { buffer += stack1; }
+ return buffer;
+},"2":function(depth0,helpers,partials,data) {
+ var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
+ return " <p><a class=\"pkt_ext_learnmore\" href=\"https://"
+ + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper)))
+ + "/firefox_learnmore?s=ffi&t=learnmore&tv=panel_control&v="
+ + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper)))
+ + "\" target=\"_blank\">"
+ + escapeExpression(((helper = (helper = helpers.learnmore || (depth0 != null ? depth0.learnmore : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"learnmore","hash":{},"data":data}) : helper)))
+ + "</a></p>\n";
+},"4":function(depth0,helpers,partials,data) {
+ var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
+ return " <p><a class=\"pkt_ext_learnmore\" href=\"https://"
+ + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper)))
+ + "/firefox_learnmore?s=ffi&t=learnmore&tv=panel_tryit&v="
+ + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper)))
+ + "\" target=\"_blank\">"
+ + escapeExpression(((helper = (helper = helpers.learnmore || (depth0 != null ? depth0.learnmore : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"learnmore","hash":{},"data":data}) : helper)))
+ + "</a></p>\n";
+},"6":function(depth0,helpers,partials,data) {
+ var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
+ return " <p><a class=\"pkt_ext_learnmore pkt_ext_learnmoreinactive\" href=\"#\">"
+ + escapeExpression(((helper = (helper = helpers.learnmore || (depth0 != null ? depth0.learnmore : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"learnmore","hash":{},"data":data}) : helper)))
+ + "</a></p>\n";
+},"8":function(depth0,helpers,partials,data) {
+ var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
+ return " <h4>"
+ + escapeExpression(((helper = (helper = helpers.signuptosave || (depth0 != null ? depth0.signuptosave : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"signuptosave","hash":{},"data":data}) : helper)))
+ + "</h4>\n <p class=\"btn-container\"><a href=\"https://"
+ + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper)))
+ + "/ff_signup?s=ffi&t=signupff&v="
+ + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper)))
+ + "\" target=\"_blank\" class=\"btn signup-btn-firefox\"><span class=\"logo\"></span><span class=\"text\">"
+ + escapeExpression(((helper = (helper = helpers.signinfirefox || (depth0 != null ? depth0.signinfirefox : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"signinfirefox","hash":{},"data":data}) : helper)))
+ + "</span></a></p>\n <p class=\"alreadyhave\">"
+ + escapeExpression(((helper = (helper = helpers.alreadyhaveacct || (depth0 != null ? depth0.alreadyhaveacct : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"alreadyhaveacct","hash":{},"data":data}) : helper)))
+ + " <a href=\"https://"
+ + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper)))
+ + "/login?ep=3&src=extension&s=ffi&t=login&v="
+ + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper)))
+ + "\" target=\"_blank\">"
+ + escapeExpression(((helper = (helper = helpers.loginnow || (depth0 != null ? depth0.loginnow : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"loginnow","hash":{},"data":data}) : helper)))
+ + "</a>.</p>\n";
+},"10":function(depth0,helpers,partials,data) {
+ var stack1, buffer = "";
+ stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.controlvariant : depth0), {"name":"if","hash":{},"fn":this.program(11, data),"inverse":this.program(13, data),"data":data});
+ if (stack1 != null) { buffer += stack1; }
+ return buffer;
+},"11":function(depth0,helpers,partials,data) {
+ var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression;
+ return " <h4>"
+ + escapeExpression(((helper = (helper = helpers.signuptosave || (depth0 != null ? depth0.signuptosave : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"signuptosave","hash":{},"data":data}) : helper)))
+ + "</h4>\n <p class=\"btn-container\"><a href=\"https://"
+ + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper)))
+ + "/ff_signup?s=ffi&tv=panel_control&t=signupff&v="
+ + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper)))
+ + "\" target=\"_blank\" class=\"btn signup-btn-firefox\"><span class=\"logo\"></span><span class=\"text\">"
+ + escapeExpression(((helper = (helper = helpers.signupfirefox || (depth0 != null ? depth0.signupfirefox : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"signupfirefox","hash":{},"data":data}) : helper)))
+ + "</span></a></p>\n <p class=\"btn-container\"><a href=\"https://"
+ + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper)))
+ + "/signup?force=email&tv=panel_control&src=extension&s=ffi&t=signupemail&v="
+ + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper)))
+ + "\" target=\"_blank\" class=\"btn btn-secondary signup-btn-email signup-btn-initstate\">"
+ + escapeExpression(((helper = (helper = helpers.signupemail || (depth0 != null ? depth0.signupemail : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"signupemail","hash":{},"data":data}) : helper)))
+ + "</a></p>\n <p class=\"alreadyhave\">"
+ + escapeExpression(((helper = (helper = helpers.alreadyhaveacct || (depth0 != null ? depth0.alreadyhaveacct : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"alreadyhaveacct","hash":{},"data":data}) : helper)))
+ + " <a href=\"https://"
+ + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper)))
+ + "/login?ep=3&tv=panel_control&src=extension&s=ffi&t=login&v="
+ + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper)))
+ + "\" target=\"_blank\">"
+ + escapeExpression(((helper = (helper = helpers.loginnow || (depth0 != null ? depth0.loginnow : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"loginnow","hash":{},"data":data}) : helper)))
+ + "</a>.</p>\n";
+},"13":function(depth0,helpers,partials,data) {
+ var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = " <p class=\"btn-container\"><a href=\"https://"
+ + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper)))
+ + "/firefox_tryitnow?s=ffi&tv=panel_tryit&t=tryitnow\" target=\"_blank\" class=\"btn signup-btn-tryitnow\"><span class=\"text\">"
+ + escapeExpression(((helper = (helper = helpers.tryitnow || (depth0 != null ? depth0.tryitnow : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"tryitnow","hash":{},"data":data}) : helper)))
+ + "</span></a></p>\n <p class=\"alreadyhave tryitnowspace\">"
+ + escapeExpression(((helper = (helper = helpers.alreadyhaveacct || (depth0 != null ? depth0.alreadyhaveacct : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"alreadyhaveacct","hash":{},"data":data}) : helper)))
+ + " <a href=\"https://"
+ + escapeExpression(((helper = (helper = helpers.pockethost || (depth0 != null ? depth0.pockethost : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"pockethost","hash":{},"data":data}) : helper)))
+ + "/login?ep=3&s=ffi&tv=panel_tryit&src=extension&t=login&v="
+ + escapeExpression(((helper = (helper = helpers.variant || (depth0 != null ? depth0.variant : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"variant","hash":{},"data":data}) : helper)))
+ + "\" target=\"_blank\">"
+ + escapeExpression(((helper = (helper = helpers.loginnow || (depth0 != null ? depth0.loginnow : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"loginnow","hash":{},"data":data}) : helper)))
+ + "</a>.</p>\n <p class=\"pkt_ext_tos\">";
+ stack1 = ((helper = (helper = helpers.tos || (depth0 != null ? depth0.tos : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"tos","hash":{},"data":data}) : helper));
+ if (stack1 != null) { buffer += stack1; }
+ return buffer + "</p>\n";
+},"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) {
+ var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = "<div class=\"pkt_ext_introdetail pkt_ext_introdetailstoryboard\">\n <div class=\"pkt_ext_introstory pkt_ext_introstoryone\">\n <div class=\"pkt_ext_introstory_text\">\n <p class=\"pkt_ext_tagline\">"
+ + escapeExpression(((helper = (helper = helpers.taglinestory_one || (depth0 != null ? depth0.taglinestory_one : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"taglinestory_one","hash":{},"data":data}) : helper)))
+ + "</p>\n </div>\n <div class=\"pkt_ext_introstoryone_img\"></div>\n </div>\n <div class=\"pkt_ext_introstorydivider\"></div>\n <div class=\"pkt_ext_introstory pkt_ext_introstorytwo\">\n <div class=\"pkt_ext_introstory_text\">\n <p class=\"pkt_ext_tagline\">"
+ + escapeExpression(((helper = (helper = helpers.taglinestory_two || (depth0 != null ? depth0.taglinestory_two : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"taglinestory_two","hash":{},"data":data}) : helper)))
+ + "</p>\n";
+ stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.showlearnmore : depth0), {"name":"if","hash":{},"fn":this.program(1, data),"inverse":this.program(6, data),"data":data});
+ if (stack1 != null) { buffer += stack1; }
+ buffer += " </div>\n <div class=\"pkt_ext_introstorytwo_img\"></div>\n </div>\n</div>\n<div class=\"pkt_ext_signupdetail\">\n";
+ stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.fxasignedin : depth0), {"name":"if","hash":{},"fn":this.program(8, data),"inverse":this.program(10, data),"data":data});
+ if (stack1 != null) { buffer += stack1; }
+ return buffer + "\n</div>\n";
+},"useData":true});
+})();
diff --git a/browser/extensions/pocket/content/panels/js/vendor/handlebars.runtime.js b/browser/extensions/pocket/content/panels/js/vendor/handlebars.runtime.js
new file mode 100644
index 000000000..c8bb1c452
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/js/vendor/handlebars.runtime.js
@@ -0,0 +1,660 @@
+/*
+
+ handlebars v2.0.0
+
+Copyright (C) 2011-2014 by Yehuda Katz
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+@license
+*/
+/* exported Handlebars */
+(function (root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ define([], factory);
+ } else if (typeof exports === 'object') {
+ module.exports = factory();
+ } else {
+ root.Handlebars = root.Handlebars || factory();
+ }
+}(this, function () {
+// handlebars/safe-string.js
+var __module3__ = (function() {
+ "use strict";
+ var __exports__;
+ // Build out our basic SafeString type
+ function SafeString(string) {
+ this.string = string;
+ }
+
+ SafeString.prototype.toString = function() {
+ return "" + this.string;
+ };
+
+ __exports__ = SafeString;
+ return __exports__;
+})();
+
+// handlebars/utils.js
+var __module2__ = (function(__dependency1__) {
+ "use strict";
+ var __exports__ = {};
+ /*jshint -W004 */
+ var SafeString = __dependency1__;
+
+ var escape = {
+ "&": "&amp;",
+ "<": "&lt;",
+ ">": "&gt;",
+ '"': "&quot;",
+ "'": "&#x27;",
+ "`": "&#x60;"
+ };
+
+ var badChars = /[&<>"'`]/g;
+ var possible = /[&<>"'`]/;
+
+ function escapeChar(chr) {
+ return escape[chr];
+ }
+
+ function extend(obj /* , ...source */) {
+ for (var i = 1; i < arguments.length; i++) {
+ for (var key in arguments[i]) {
+ if (Object.prototype.hasOwnProperty.call(arguments[i], key)) {
+ obj[key] = arguments[i][key];
+ }
+ }
+ }
+
+ return obj;
+ }
+
+ __exports__.extend = extend;var toString = Object.prototype.toString;
+ __exports__.toString = toString;
+ // Sourced from lodash
+ // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt
+ var isFunction = function(value) {
+ return typeof value === 'function';
+ };
+ // fallback for older versions of Chrome and Safari
+ /* istanbul ignore next */
+ if (isFunction(/x/)) {
+ isFunction = function(value) {
+ return typeof value === 'function' && toString.call(value) === '[object Function]';
+ };
+ }
+ var isFunction;
+ __exports__.isFunction = isFunction;
+ /* istanbul ignore next */
+ var isArray = Array.isArray || function(value) {
+ return (value && typeof value === 'object') ? toString.call(value) === '[object Array]' : false;
+ };
+ __exports__.isArray = isArray;
+
+ function escapeExpression(string) {
+ // don't escape SafeStrings, since they're already safe
+ if (string instanceof SafeString) {
+ return string.toString();
+ } else if (string == null) {
+ return "";
+ } else if (!string) {
+ return string + '';
+ }
+
+ // Force a string conversion as this will be done by the append regardless and
+ // the regex test will do this transparently behind the scenes, causing issues if
+ // an object's to string has escaped characters in it.
+ string = "" + string;
+
+ if(!possible.test(string)) { return string; }
+ return string.replace(badChars, escapeChar);
+ }
+
+ __exports__.escapeExpression = escapeExpression;function isEmpty(value) {
+ if (!value && value !== 0) {
+ return true;
+ } else if (isArray(value) && value.length === 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ __exports__.isEmpty = isEmpty;function appendContextPath(contextPath, id) {
+ return (contextPath ? contextPath + '.' : '') + id;
+ }
+
+ __exports__.appendContextPath = appendContextPath;
+ return __exports__;
+})(__module3__);
+
+// handlebars/exception.js
+var __module4__ = (function() {
+ "use strict";
+ var __exports__;
+
+ var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack'];
+
+ function Exception(message, node) {
+ var line;
+ if (node && node.firstLine) {
+ line = node.firstLine;
+
+ message += ' - ' + line + ':' + node.firstColumn;
+ }
+
+ var tmp = Error.prototype.constructor.call(this, message);
+
+ // Unfortunately errors are not enumerable in Chrome (at least), so `for prop in tmp` doesn't work.
+ for (var idx = 0; idx < errorProps.length; idx++) {
+ this[errorProps[idx]] = tmp[errorProps[idx]];
+ }
+
+ if (line) {
+ this.lineNumber = line;
+ this.column = node.firstColumn;
+ }
+ }
+
+ Exception.prototype = new Error();
+
+ __exports__ = Exception;
+ return __exports__;
+})();
+
+// handlebars/base.js
+var __module1__ = (function(__dependency1__, __dependency2__) {
+ "use strict";
+ var __exports__ = {};
+ var Utils = __dependency1__;
+ var Exception = __dependency2__;
+
+ var VERSION = "2.0.0";
+ __exports__.VERSION = VERSION;var COMPILER_REVISION = 6;
+ __exports__.COMPILER_REVISION = COMPILER_REVISION;
+ var REVISION_CHANGES = {
+ 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
+ 2: '== 1.0.0-rc.3',
+ 3: '== 1.0.0-rc.4',
+ 4: '== 1.x.x',
+ 5: '== 2.0.0-alpha.x',
+ 6: '>= 2.0.0-beta.1'
+ };
+ __exports__.REVISION_CHANGES = REVISION_CHANGES;
+ var isArray = Utils.isArray,
+ isFunction = Utils.isFunction,
+ toString = Utils.toString,
+ objectType = '[object Object]';
+
+ function HandlebarsEnvironment(helpers, partials) {
+ this.helpers = helpers || {};
+ this.partials = partials || {};
+
+ registerDefaultHelpers(this);
+ }
+
+ __exports__.HandlebarsEnvironment = HandlebarsEnvironment;HandlebarsEnvironment.prototype = {
+ constructor: HandlebarsEnvironment,
+
+ logger: logger,
+ log: log,
+
+ registerHelper: function(name, fn) {
+ if (toString.call(name) === objectType) {
+ if (fn) { throw new Exception('Arg not supported with multiple helpers'); }
+ Utils.extend(this.helpers, name);
+ } else {
+ this.helpers[name] = fn;
+ }
+ },
+ unregisterHelper: function(name) {
+ delete this.helpers[name];
+ },
+
+ registerPartial: function(name, partial) {
+ if (toString.call(name) === objectType) {
+ Utils.extend(this.partials, name);
+ } else {
+ this.partials[name] = partial;
+ }
+ },
+ unregisterPartial: function(name) {
+ delete this.partials[name];
+ }
+ };
+
+ function registerDefaultHelpers(instance) {
+ instance.registerHelper('helperMissing', function(/* [args, ]options */) {
+ if(arguments.length === 1) {
+ // A missing field in a {{foo}} constuct.
+ return undefined;
+ } else {
+ // Someone is actually trying to call something, blow up.
+ throw new Exception("Missing helper: '" + arguments[arguments.length-1].name + "'");
+ }
+ });
+
+ instance.registerHelper('blockHelperMissing', function(context, options) {
+ var inverse = options.inverse,
+ fn = options.fn;
+
+ if(context === true) {
+ return fn(this);
+ } else if(context === false || context == null) {
+ return inverse(this);
+ } else if (isArray(context)) {
+ if(context.length > 0) {
+ if (options.ids) {
+ options.ids = [options.name];
+ }
+
+ return instance.helpers.each(context, options);
+ } else {
+ return inverse(this);
+ }
+ } else {
+ if (options.data && options.ids) {
+ var data = createFrame(options.data);
+ data.contextPath = Utils.appendContextPath(options.data.contextPath, options.name);
+ options = {data: data};
+ }
+
+ return fn(context, options);
+ }
+ });
+
+ instance.registerHelper('each', function(context, options) {
+ if (!options) {
+ throw new Exception('Must pass iterator to #each');
+ }
+
+ var fn = options.fn, inverse = options.inverse;
+ var i = 0, ret = "", data;
+
+ var contextPath;
+ if (options.data && options.ids) {
+ contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]) + '.';
+ }
+
+ if (isFunction(context)) { context = context.call(this); }
+
+ if (options.data) {
+ data = createFrame(options.data);
+ }
+
+ if(context && typeof context === 'object') {
+ if (isArray(context)) {
+ for(var j = context.length; i<j; i++) {
+ if (data) {
+ data.index = i;
+ data.first = (i === 0);
+ data.last = (i === (context.length-1));
+
+ if (contextPath) {
+ data.contextPath = contextPath + i;
+ }
+ }
+ ret = ret + fn(context[i], { data: data });
+ }
+ } else {
+ for(var key in context) {
+ if(context.hasOwnProperty(key)) {
+ if(data) {
+ data.key = key;
+ data.index = i;
+ data.first = (i === 0);
+
+ if (contextPath) {
+ data.contextPath = contextPath + key;
+ }
+ }
+ ret = ret + fn(context[key], {data: data});
+ i++;
+ }
+ }
+ }
+ }
+
+ if(i === 0){
+ ret = inverse(this);
+ }
+
+ return ret;
+ });
+
+ instance.registerHelper('if', function(conditional, options) {
+ if (isFunction(conditional)) { conditional = conditional.call(this); }
+
+ // Default behavior is to render the positive path if the value is truthy and not empty.
+ // The `includeZero` option may be set to treat the condtional as purely not empty based on the
+ // behavior of isEmpty. Effectively this determines if 0 is handled by the positive path or negative.
+ if ((!options.hash.includeZero && !conditional) || Utils.isEmpty(conditional)) {
+ return options.inverse(this);
+ } else {
+ return options.fn(this);
+ }
+ });
+
+ instance.registerHelper('unless', function(conditional, options) {
+ return instance.helpers['if'].call(this, conditional, {fn: options.inverse, inverse: options.fn, hash: options.hash});
+ });
+
+ instance.registerHelper('with', function(context, options) {
+ if (isFunction(context)) { context = context.call(this); }
+
+ var fn = options.fn;
+
+ if (!Utils.isEmpty(context)) {
+ if (options.data && options.ids) {
+ var data = createFrame(options.data);
+ data.contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]);
+ options = {data:data};
+ }
+
+ return fn(context, options);
+ } else {
+ return options.inverse(this);
+ }
+ });
+
+ instance.registerHelper('log', function(message, options) {
+ var level = options.data && options.data.level != null ? parseInt(options.data.level, 10) : 1;
+ instance.log(level, message);
+ });
+
+ instance.registerHelper('lookup', function(obj, field) {
+ return obj && obj[field];
+ });
+ }
+
+ var logger = {
+ methodMap: { 0: 'debug', 1: 'info', 2: 'warn', 3: 'error' },
+
+ // State enum
+ DEBUG: 0,
+ INFO: 1,
+ WARN: 2,
+ ERROR: 3,
+ level: 3,
+
+ // can be overridden in the host environment
+ log: function(level, message) {
+ if (logger.level <= level) {
+ var method = logger.methodMap[level];
+ if (typeof console !== 'undefined' && console[method]) {
+ console[method].call(console, message);
+ }
+ }
+ }
+ };
+ __exports__.logger = logger;
+ var log = logger.log;
+ __exports__.log = log;
+ var createFrame = function(object) {
+ var frame = Utils.extend({}, object);
+ frame._parent = object;
+ return frame;
+ };
+ __exports__.createFrame = createFrame;
+ return __exports__;
+})(__module2__, __module4__);
+
+// handlebars/runtime.js
+var __module5__ = (function(__dependency1__, __dependency2__, __dependency3__) {
+ "use strict";
+ var __exports__ = {};
+ var Utils = __dependency1__;
+ var Exception = __dependency2__;
+ var COMPILER_REVISION = __dependency3__.COMPILER_REVISION;
+ var REVISION_CHANGES = __dependency3__.REVISION_CHANGES;
+ var createFrame = __dependency3__.createFrame;
+
+ function checkRevision(compilerInfo) {
+ var compilerRevision = compilerInfo && compilerInfo[0] || 1,
+ currentRevision = COMPILER_REVISION;
+
+ if (compilerRevision !== currentRevision) {
+ if (compilerRevision < currentRevision) {
+ var runtimeVersions = REVISION_CHANGES[currentRevision],
+ compilerVersions = REVISION_CHANGES[compilerRevision];
+ throw new Exception("Template was precompiled with an older version of Handlebars than the current runtime. "+
+ "Please update your precompiler to a newer version ("+runtimeVersions+") or downgrade your runtime to an older version ("+compilerVersions+").");
+ } else {
+ // Use the embedded version info since the runtime doesn't know about this revision yet
+ throw new Exception("Template was precompiled with a newer version of Handlebars than the current runtime. "+
+ "Please update your runtime to a newer version ("+compilerInfo[1]+").");
+ }
+ }
+ }
+
+ __exports__.checkRevision = checkRevision;// TODO: Remove this line and break up compilePartial
+
+ function template(templateSpec, env) {
+ /* istanbul ignore next */
+ if (!env) {
+ throw new Exception("No environment passed to template");
+ }
+ if (!templateSpec || !templateSpec.main) {
+ throw new Exception('Unknown template object: ' + typeof templateSpec);
+ }
+
+ // Note: Using env.VM references rather than local var references throughout this section to allow
+ // for external users to override these as psuedo-supported APIs.
+ env.VM.checkRevision(templateSpec.compiler);
+
+ var invokePartialWrapper = function(partial, indent, name, context, hash, helpers, partials, data, depths) {
+ if (hash) {
+ context = Utils.extend({}, context, hash);
+ }
+
+ var result = env.VM.invokePartial.call(this, partial, name, context, helpers, partials, data, depths);
+
+ if (result == null && env.compile) {
+ var options = { helpers: helpers, partials: partials, data: data, depths: depths };
+ partials[name] = env.compile(partial, { data: data !== undefined, compat: templateSpec.compat }, env);
+ result = partials[name](context, options);
+ }
+ if (result != null) {
+ if (indent) {
+ var lines = result.split('\n');
+ for (var i = 0, l = lines.length; i < l; i++) {
+ if (!lines[i] && i + 1 === l) {
+ break;
+ }
+
+ lines[i] = indent + lines[i];
+ }
+ result = lines.join('\n');
+ }
+ return result;
+ } else {
+ throw new Exception("The partial " + name + " could not be compiled when running in runtime-only mode");
+ }
+ };
+
+ // Just add water
+ var container = {
+ lookup: function(depths, name) {
+ var len = depths.length;
+ for (var i = 0; i < len; i++) {
+ if (depths[i] && depths[i][name] != null) {
+ return depths[i][name];
+ }
+ }
+ },
+ lambda: function(current, context) {
+ return typeof current === 'function' ? current.call(context) : current;
+ },
+
+ escapeExpression: Utils.escapeExpression,
+ invokePartial: invokePartialWrapper,
+
+ fn: function(i) {
+ return templateSpec[i];
+ },
+
+ programs: [],
+ program: function(i, data, depths) {
+ var programWrapper = this.programs[i],
+ fn = this.fn(i);
+ if (data || depths) {
+ programWrapper = program(this, i, fn, data, depths);
+ } else if (!programWrapper) {
+ programWrapper = this.programs[i] = program(this, i, fn);
+ }
+ return programWrapper;
+ },
+
+ data: function(data, depth) {
+ while (data && depth--) {
+ data = data._parent;
+ }
+ return data;
+ },
+ merge: function(param, common) {
+ var ret = param || common;
+
+ if (param && common && (param !== common)) {
+ ret = Utils.extend({}, common, param);
+ }
+
+ return ret;
+ },
+
+ noop: env.VM.noop,
+ compilerInfo: templateSpec.compiler
+ };
+
+ var ret = function(context, options) {
+ options = options || {};
+ var data = options.data;
+
+ ret._setup(options);
+ if (!options.partial && templateSpec.useData) {
+ data = initData(context, data);
+ }
+ var depths;
+ if (templateSpec.useDepths) {
+ depths = options.depths ? [context].concat(options.depths) : [context];
+ }
+
+ return templateSpec.main.call(container, context, container.helpers, container.partials, data, depths);
+ };
+ ret.isTop = true;
+
+ ret._setup = function(options) {
+ if (!options.partial) {
+ container.helpers = container.merge(options.helpers, env.helpers);
+
+ if (templateSpec.usePartial) {
+ container.partials = container.merge(options.partials, env.partials);
+ }
+ } else {
+ container.helpers = options.helpers;
+ container.partials = options.partials;
+ }
+ };
+
+ ret._child = function(i, data, depths) {
+ if (templateSpec.useDepths && !depths) {
+ throw new Exception('must pass parent depths');
+ }
+
+ return program(container, i, templateSpec[i], data, depths);
+ };
+ return ret;
+ }
+
+ __exports__.template = template;function program(container, i, fn, data, depths) {
+ var prog = function(context, options) {
+ options = options || {};
+
+ return fn.call(container, context, container.helpers, container.partials, options.data || data, depths && [context].concat(depths));
+ };
+ prog.program = i;
+ prog.depth = depths ? depths.length : 0;
+ return prog;
+ }
+
+ __exports__.program = program;function invokePartial(partial, name, context, helpers, partials, data, depths) {
+ var options = { partial: true, helpers: helpers, partials: partials, data: data, depths: depths };
+
+ if(partial === undefined) {
+ throw new Exception("The partial " + name + " could not be found");
+ } else if(partial instanceof Function) {
+ return partial(context, options);
+ }
+ }
+
+ __exports__.invokePartial = invokePartial;function noop() { return ""; }
+
+ __exports__.noop = noop;function initData(context, data) {
+ if (!data || !('root' in data)) {
+ data = data ? createFrame(data) : {};
+ data.root = context;
+ }
+ return data;
+ }
+ return __exports__;
+})(__module2__, __module4__, __module1__);
+
+// handlebars.runtime.js
+var __module0__ = (function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__) {
+ "use strict";
+ var __exports__;
+ /*globals Handlebars: true */
+ var base = __dependency1__;
+
+ // Each of these augment the Handlebars object. No need to setup here.
+ // (This is done to easily share code between commonjs and browse envs)
+ var SafeString = __dependency2__;
+ var Exception = __dependency3__;
+ var Utils = __dependency4__;
+ var runtime = __dependency5__;
+
+ // For compatibility and usage outside of module systems, make the Handlebars object a namespace
+ var create = function() {
+ var hb = new base.HandlebarsEnvironment();
+
+ Utils.extend(hb, base);
+ hb.SafeString = SafeString;
+ hb.Exception = Exception;
+ hb.Utils = Utils;
+ hb.escapeExpression = Utils.escapeExpression;
+
+ hb.VM = runtime;
+ hb.template = function(spec) {
+ return runtime.template(spec, hb);
+ };
+
+ return hb;
+ };
+
+ var Handlebars = create();
+ Handlebars.create = create;
+
+ Handlebars['default'] = Handlebars;
+
+ __exports__ = Handlebars;
+ return __exports__;
+})(__module1__, __module3__, __module4__, __module2__, __module5__);
+
+ return __module0__;
+}));
diff --git a/browser/extensions/pocket/content/panels/js/vendor/jquery-2.1.1.min.js b/browser/extensions/pocket/content/panels/js/vendor/jquery-2.1.1.min.js
new file mode 100644
index 000000000..9ed2acc66
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/js/vendor/jquery-2.1.1.min.js
@@ -0,0 +1,4 @@
+/*! jQuery v2.1.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
+!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.1",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="<div class='a'></div><div class='a i'></div>",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="<select msallowclip=''><option selected=''></option></select>",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=lb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=mb(b);function pb(){}pb.prototype=d.filters=d.pseudos,d.setFilters=new pb,g=fb.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=S.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=T.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(R," ")}),h=h.slice(c.length));for(g in d.filter)!(e=X[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?fb.error(a):z(a,i).slice(0)};function qb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+Math.random()}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b)
+},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=L.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var Q=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,R=["Top","Right","Bottom","Left"],S=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)},T=/^(?:checkbox|radio)$/i;!function(){var a=l.createDocumentFragment(),b=a.appendChild(l.createElement("div")),c=l.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button;return null==a.pageX&&null!=b.clientX&&(c=a.target.ownerDocument||l,d=c.documentElement,e=c.body,a.pageX=b.clientX+(d&&d.scrollLeft||e&&e.scrollLeft||0)-(d&&d.clientLeft||e&&e.clientLeft||0),a.pageY=b.clientY+(d&&d.scrollTop||e&&e.scrollTop||0)-(d&&d.clientTop||e&&e.clientTop||0)),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},fix:function(a){if(a[n.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=W.test(e)?this.mouseHooks:V.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new n.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=l),3===a.target.nodeType&&(a.target=a.target.parentNode),g.filter?g.filter(a,f):a},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==_()&&this.focus?(this.focus(),!1):void 0},delegateType:"focusin"},blur:{trigger:function(){return this===_()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&n.nodeName(this,"input")?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=n.extend(new n.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?n.event.trigger(e,null,b):n.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},n.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?Z:$):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={isDefaultPrevented:$,isPropagationStopped:$,isImmediatePropagationStopped:$,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=Z,a&&a.preventDefault&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=Z,a&&a.stopPropagation&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=Z,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},n.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!n.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),k.focusinBubbles||n.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a),!0)};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=L.access(d,b);e||d.addEventListener(a,c,!0),L.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=L.access(d,b)-1;e?L.access(d,b,e):(d.removeEventListener(a,c,!0),L.remove(d,b))}}}),n.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(g in a)this.on(g,b,c,a[g],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=$;else if(!d)return this;return 1===e&&(f=d,d=function(a){return n().off(a),f.apply(this,arguments)},d.guid=f.guid||(f.guid=n.guid++)),this.each(function(){n.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=$),this.each(function(){n.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}});var ab=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ib={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1></$2>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(ob(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(ob(c,"script"),kb),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(hb,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function tb(a){var b=l,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||n("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=qb[0].contentDocument,b.write(),b.close(),c=sb(a,b),qb.detach()),rb[a]=c),c}var ub=/^margin/,vb=new RegExp("^("+Q+")(?!px)[a-z%]+$","i"),wb=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)};function xb(a,b,c){var d,e,f,g,h=a.style;return c=c||wb(a),c&&(g=c.getPropertyValue(b)||c[b]),c&&(""!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),vb.test(g)&&ub.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function yb(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d=l.documentElement,e=l.createElement("div"),f=l.createElement("div");if(f.style){f.style.backgroundClip="content-box",f.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===f.style.backgroundClip,e.style.cssText="border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;position:absolute",e.appendChild(f);function g(){f.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",f.innerHTML="",d.appendChild(e);var g=a.getComputedStyle(f,null);b="1%"!==g.top,c="4px"===g.width,d.removeChild(e)}a.getComputedStyle&&n.extend(k,{pixelPosition:function(){return g(),b},boxSizingReliable:function(){return null==c&&g(),c},reliableMarginRight:function(){var b,c=f.appendChild(l.createElement("div"));return c.style.cssText=f.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",c.style.marginRight=c.style.width="0",f.style.width="1px",d.appendChild(e),b=!parseFloat(a.getComputedStyle(c,null).marginRight),d.removeChild(e),b}})}}(),n.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var zb=/^(none|table(?!-c[ea]).+)/,Ab=new RegExp("^("+Q+")(.*)$","i"),Bb=new RegExp("^([+-])=("+Q+")","i"),Cb={position:"absolute",visibility:"hidden",display:"block"},Db={letterSpacing:"0",fontWeight:"400"},Eb=["Webkit","O","Moz","ms"];function Fb(a,b){if(b in a)return b;var c=b[0].toUpperCase()+b.slice(1),d=b,e=Eb.length;while(e--)if(b=Eb[e]+c,b in a)return b;return d}function Gb(a,b,c){var d=Ab.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Hb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+R[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+R[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+R[f]+"Width",!0,e))):(g+=n.css(a,"padding"+R[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+R[f]+"Width",!0,e)));return g}function Ib(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=wb(a),g="border-box"===n.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=xb(a,b,f),(0>e||null==e)&&(e=a.style[b]),vb.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Hb(a,b,c||(g?"border":"content"),d,f)+"px"}function Jb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=L.get(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&S(d)&&(f[g]=L.access(d,"olddisplay",tb(d.nodeName)))):(e=S(d),"none"===c&&e||L.set(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=xb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;return b=n.cssProps[h]||(n.cssProps[h]=Fb(i,h)),g=n.cssHooks[b]||n.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=Bb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(n.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||n.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=Fb(a.style,h)),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=xb(a,b,d)),"normal"===e&&b in Db&&(e=Db[b]),""===c||c?(f=parseFloat(e),c===!0||n.isNumeric(f)?f||0:e):e}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?zb.test(n.css(a,"display"))&&0===a.offsetWidth?n.swap(a,Cb,function(){return Ib(a,b,d)}):Ib(a,b,d):void 0},set:function(a,c,d){var e=d&&wb(a);return Gb(a,c,d?Hb(a,b,d,"border-box"===n.css(a,"boxSizing",!1,e),e):0)}}}),n.cssHooks.marginRight=yb(k.reliableMarginRight,function(a,b){return b?n.swap(a,{display:"inline-block"},xb,[a,"marginRight"]):void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+R[d]+b]=f[d]||f[d-2]||f[0];return e}},ub.test(a)||(n.cssHooks[a+b].set=Gb)}),n.fn.extend({css:function(a,b){return J(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=wb(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)},a,b,arguments.length>1)},show:function(){return Jb(this,!0)},hide:function(){return Jb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){S(this)?n(this).show():n(this).hide()})}});function Kb(a,b,c,d,e){return new Kb.prototype.init(a,b,c,d,e)}n.Tween=Kb,Kb.prototype={constructor:Kb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=Kb.propHooks[this.prop];return a&&a.get?a.get(this):Kb.propHooks._default.get(this)},run:function(a){var b,c=Kb.propHooks[this.prop];return this.pos=b=this.options.duration?n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Kb.propHooks._default.set(this),this}},Kb.prototype.init.prototype=Kb.prototype,Kb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[n.cssProps[a.prop]]||n.cssHooks[a.prop])?n.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Kb.propHooks.scrollTop=Kb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},n.fx=Kb.prototype.init,n.fx.step={};var Lb,Mb,Nb=/^(?:toggle|show|hide)$/,Ob=new RegExp("^(?:([+-])=|)("+Q+")([a-z%]*)$","i"),Pb=/queueHooks$/,Qb=[Vb],Rb={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=Ob.exec(b),f=e&&e[3]||(n.cssNumber[a]?"":"px"),g=(n.cssNumber[a]||"px"!==f&&+d)&&Ob.exec(n.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,n.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function Sb(){return setTimeout(function(){Lb=void 0}),Lb=n.now()}function Tb(a,b){var c,d=0,e={height:a};for(b=b?1:0;4>d;d+=2-b)c=R[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function Ub(a,b,c){for(var d,e=(Rb[b]||[]).concat(Rb["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function Vb(a,b,c){var d,e,f,g,h,i,j,k,l=this,m={},o=a.style,p=a.nodeType&&S(a),q=L.get(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,l.always(function(){l.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=n.css(a,"display"),k="none"===j?L.get(a,"olddisplay")||tb(a.nodeName):j,"inline"===k&&"none"===n.css(a,"float")&&(o.display="inline-block")),c.overflow&&(o.overflow="hidden",l.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],Nb.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}m[d]=q&&q[d]||n.style(a,d)}else j=void 0;if(n.isEmptyObject(m))"inline"===("none"===j?tb(a.nodeName):j)&&(o.display=j);else{q?"hidden"in q&&(p=q.hidden):q=L.access(a,"fxshow",{}),f&&(q.hidden=!p),p?n(a).show():l.done(function(){n(a).hide()}),l.done(function(){var b;L.remove(a,"fxshow");for(b in m)n.style(a,b,m[b])});for(d in m)g=Ub(p?q[d]:0,d,l),d in q||(q[d]=g.start,p&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function Wb(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function Xb(a,b,c){var d,e,f=0,g=Qb.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=Lb||Sb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:Lb||Sb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(Wb(k,j.opts.specialEasing);g>f;f++)if(d=Qb[f].call(j,a,k,j.opts))return d;return n.map(k,Ub,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(Xb,{tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],Rb[c]=Rb[c]||[],Rb[c].unshift(b)},prefilter:function(a,b){b?Qb.unshift(a):Qb.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(S).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=Xb(this,n.extend({},a),f);(e||L.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=L.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&Pb.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=L.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(Tb(b,!0),a,d,e)}}),n.each({slideDown:Tb("show"),slideUp:Tb("hide"),slideToggle:Tb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=0,c=n.timers;for(Lb=n.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||n.fx.stop(),Lb=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){Mb||(Mb=setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){clearInterval(Mb),Mb=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(a,b){return a=n.fx?n.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a=l.createElement("input"),b=l.createElement("select"),c=b.appendChild(l.createElement("option"));a.type="checkbox",k.checkOn=""!==a.value,k.optSelected=c.selected,b.disabled=!0,k.optDisabled=!c.disabled,a=l.createElement("input"),a.value="t",a.type="radio",k.radioValue="t"===a.value}();var Yb,Zb,$b=n.expr.attrHandle;n.fn.extend({attr:function(a,b){return J(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===U?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),d=n.attrHooks[b]||(n.expr.match.bool.test(b)?Zb:Yb)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=n.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void n.removeAttr(a,b))
+},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)&&(a[d]=!1),a.removeAttribute(c)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),Zb={set:function(a,b,c){return b===!1?n.removeAttr(a,c):a.setAttribute(c,c),c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=$b[b]||n.find.attr;$b[b]=function(a,b,d){var e,f;return d||(f=$b[b],$b[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,$b[b]=f),e}});var _b=/^(?:input|select|textarea|button)$/i;n.fn.extend({prop:function(a,b){return J(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[n.propFix[a]||a]})}}),n.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!n.isXMLDoc(a),f&&(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){return a.hasAttribute("tabindex")||_b.test(a.nodeName)||a.href?a.tabIndex:-1}}}}),k.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this});var ac=/[\t\r\n\f]/g;n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h="string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=n.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0===arguments.length||"string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?n.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(n.isFunction(a)?function(c){n(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=n(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===U||"boolean"===c)&&(this.className&&L.set(this,"__className__",this.className),this.className=this.className||a===!1?"":L.get(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ac," ").indexOf(b)>=0)return!0;return!1}});var bc=/\r/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(bc,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.trim(n.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=n.inArray(d.value,f)>=0)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>=0:void 0}},k.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})}),n.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var cc=n.now(),dc=/\?/;n.parseJSON=function(a){return JSON.parse(a+"")},n.parseXML=function(a){var b,c;if(!a||"string"!=typeof a)return null;try{c=new DOMParser,b=c.parseFromString(a,"text/xml")}catch(d){b=void 0}return(!b||b.getElementsByTagName("parsererror").length)&&n.error("Invalid XML: "+a),b};var ec,fc,gc=/#.*$/,hc=/([?&])_=[^&]*/,ic=/^(.*?):[ \t]*([^\r\n]*)$/gm,jc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,kc=/^(?:GET|HEAD)$/,lc=/^\/\//,mc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,nc={},oc={},pc="*/".concat("*");try{fc=location.href}catch(qc){fc=l.createElement("a"),fc.href="",fc=fc.href}ec=mc.exec(fc.toLowerCase())||[];function rc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(n.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function sc(a,b,c,d){var e={},f=a===oc;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function tc(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&n.extend(!0,a,d),a}function uc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function vc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:fc,type:"GET",isLocal:jc.test(ec[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":pc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?tc(tc(a,n.ajaxSettings),b):tc(n.ajaxSettings,a)},ajaxPrefilter:rc(nc),ajaxTransport:rc(oc),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=n.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?n(l):n.event,o=n.Deferred(),p=n.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!f){f={};while(b=ic.exec(e))f[b[1].toLowerCase()]=b[2]}b=f[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?e:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return c&&c.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||fc)+"").replace(gc,"").replace(lc,ec[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=n.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(h=mc.exec(k.url.toLowerCase()),k.crossDomain=!(!h||h[1]===ec[1]&&h[2]===ec[2]&&(h[3]||("http:"===h[1]?"80":"443"))===(ec[3]||("http:"===ec[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=n.param(k.data,k.traditional)),sc(nc,k,b,v),2===t)return v;i=k.global,i&&0===n.active++&&n.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!kc.test(k.type),d=k.url,k.hasContent||(k.data&&(d=k.url+=(dc.test(d)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=hc.test(d)?d.replace(hc,"$1_="+cc++):d+(dc.test(d)?"&":"?")+"_="+cc++)),k.ifModified&&(n.lastModified[d]&&v.setRequestHeader("If-Modified-Since",n.lastModified[d]),n.etag[d]&&v.setRequestHeader("If-None-Match",n.etag[d])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+pc+"; q=0.01":""):k.accepts["*"]);for(j in k.headers)v.setRequestHeader(j,k.headers[j]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(j in{success:1,error:1,complete:1})v[j](k[j]);if(c=sc(oc,k,b,v)){v.readyState=1,i&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,c.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,f,h){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),c=void 0,e=h||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,f&&(u=uc(k,v,f)),u=vc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(n.lastModified[d]=w),w=v.getResponseHeader("etag"),w&&(n.etag[d]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,i&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),i&&(m.trigger("ajaxComplete",[v,k]),--n.active||n.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){var b;return n.isFunction(a)?this.each(function(b){n(this).wrapAll(a.call(this,b))}):(this[0]&&(b=n(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this)},wrapInner:function(a){return this.each(n.isFunction(a)?function(b){n(this).wrapInner(a.call(this,b))}:function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}}),n.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var wc=/%20/g,xc=/\[\]$/,yc=/\r?\n/g,zc=/^(?:submit|button|image|reset|file)$/i,Ac=/^(?:input|select|textarea|keygen)/i;function Bc(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||xc.test(a)?d(a,e):Bc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)Bc(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)Bc(c,a[c],b,e);return d.join("&").replace(wc,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&Ac.test(this.nodeName)&&!zc.test(a)&&(this.checked||!T.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(yc,"\r\n")}}):{name:b.name,value:c.replace(yc,"\r\n")}}).get()}}),n.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(a){}};var Cc=0,Dc={},Ec={0:200,1223:204},Fc=n.ajaxSettings.xhr();a.ActiveXObject&&n(a).on("unload",function(){for(var a in Dc)Dc[a]()}),k.cors=!!Fc&&"withCredentials"in Fc,k.ajax=Fc=!!Fc,n.ajaxTransport(function(a){var b;return k.cors||Fc&&!a.crossDomain?{send:function(c,d){var e,f=a.xhr(),g=++Cc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)f.setRequestHeader(e,c[e]);b=function(a){return function(){b&&(delete Dc[g],b=f.onload=f.onerror=null,"abort"===a?f.abort():"error"===a?d(f.status,f.statusText):d(Ec[f.status]||f.status,f.statusText,"string"==typeof f.responseText?{text:f.responseText}:void 0,f.getAllResponseHeaders()))}},f.onload=b(),f.onerror=b("error"),b=Dc[g]=b("abort");try{f.send(a.hasContent&&a.data||null)}catch(h){if(b)throw h}},abort:function(){b&&b()}}:void 0}),n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(d,e){b=n("<script>").prop({async:!0,charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&e("error"===a.type?404:200,a.type)}),l.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Gc=[],Hc=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Gc.pop()||n.expando+"_"+cc++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Hc.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Hc.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Hc,"$1"+e):b.jsonp!==!1&&(b.url+=(dc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Gc.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||l;var d=v.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=n.buildFragment([a],b,e),e&&e.length&&n(e).remove(),n.merge([],d.childNodes))};var Ic=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&Ic)return Ic.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=n.trim(a.slice(h)),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&n.ajax({url:a,type:e,dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?n("<div>").append(n.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,f||[a.responseText,b,a])}),this},n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};var Jc=a.document.documentElement;function Kc(a){return n.isWindow(a)?a:9===a.nodeType&&a.defaultView}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d=this[0],e={top:0,left:0},f=d&&d.ownerDocument;if(f)return b=f.documentElement,n.contains(b,d)?(typeof d.getBoundingClientRect!==U&&(e=d.getBoundingClientRect()),c=Kc(f),{top:e.top+c.pageYOffset-b.clientTop,left:e.left+c.pageXOffset-b.clientLeft}):e},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===n.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(d=a.offset()),d.top+=n.css(a[0],"borderTopWidth",!0),d.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-d.top-n.css(c,"marginTop",!0),left:b.left-d.left-n.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||Jc;while(a&&!n.nodeName(a,"html")&&"static"===n.css(a,"position"))a=a.offsetParent;return a||Jc})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(b,c){var d="pageYOffset"===c;n.fn[b]=function(e){return J(this,function(b,e,f){var g=Kc(b);return void 0===f?g?g[c]:b[e]:void(g?g.scrollTo(d?a.pageXOffset:f,d?f:a.pageYOffset):b[e]=f)},b,e,arguments.length,null)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=yb(k.pixelPosition,function(a,c){return c?(c=xb(a,b),vb.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return J(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var Lc=a.jQuery,Mc=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=Mc),b&&a.jQuery===n&&(a.jQuery=Lc),n},typeof b===U&&(a.jQuery=a.$=n),n}); \ No newline at end of file
diff --git a/browser/extensions/pocket/content/panels/js/vendor/jquery.tokeninput.min.js b/browser/extensions/pocket/content/panels/js/vendor/jquery.tokeninput.min.js
new file mode 100644
index 000000000..40d323df0
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/js/vendor/jquery.tokeninput.min.js
@@ -0,0 +1,954 @@
+/*
+ * jQuery Plugin: Tokenizing Autocomplete Text Entry
+ * Version 1.6.0
+ *
+ * Copyright (c) 2009 James Smith (http://loopj.com)
+ * Licensed jointly under the GPL and MIT licenses,
+ * choose which one suits your project best!
+ *
+ * Licensed under MIT
+ * With modifications
+ *
+ */
+
+(function ($) {
+// Default settings
+var DEFAULT_SETTINGS = {
+ // Search settings
+ method: "GET",
+ contentType: "json",
+ queryParam: "q",
+ searchDelay: 300,
+ minChars: 1,
+ propertyToSearch: "name",
+ jsonContainer: null,
+ scrollKeyboard: false,
+
+ // Display settings
+ hintText: null,
+ noResultsText: null,
+ noResultsHideDropdown: false,
+ searchingText: null,
+ deleteText: "&times;",
+ animateDropdown: true,
+ emptyInputLength: null,
+
+ // Tokenization settings
+ tokenLimit: null,
+ tokenDelimiter: ",",
+ preventDuplicates: false,
+
+ // Output settings
+ tokenValue: "id",
+
+ // Prepopulation settings
+ prePopulate: null,
+ processPrePopulate: false,
+
+ // Manipulation settings
+ idPrefix: "token-input-",
+
+ // Formatters
+ resultsFormatter: function(item) {
+ let listItem = document.createElement("li");
+ listItem.textContent = item[this.propertyToSearch];
+ return listItem.outerHTML;
+ },
+ tokenFormatter: function(item) {
+ let listItem = document.createElement("li");
+ let p = document.createElement("p");
+ p.textContent = item[this.propertyToSearch];
+ listItem.appendChild(p);
+ return listItem.outerHTML;
+ },
+
+ // Validations
+ validateItem: null,
+
+ // Force selections only on mouse click
+ noHoverSelect: false,
+
+ // Callbacks
+ onResult: null,
+ onAdd: null,
+ onDelete: null,
+ onReady: null
+};
+
+// Default classes to use when theming
+var DEFAULT_CLASSES = {
+ tokenList: "token-input-list",
+ token: "token-input-token",
+ tokenDelete: "token-input-delete-token",
+ selectedToken: "token-input-selected-token",
+ highlightedToken: "token-input-highlighted-token",
+ dropdown: "token-input-dropdown",
+ dropdownItem: "token-input-dropdown-item",
+ dropdownItem2: "token-input-dropdown-item2",
+ selectedDropdownItem: "token-input-selected-dropdown-item",
+ inputToken: "token-input-input-token"
+};
+
+// Input box position "enum"
+var POSITION = {
+ BEFORE: 0,
+ AFTER: 1,
+ END: 2
+};
+
+// Keys "enum"
+var KEY = {
+ BACKSPACE: 8,
+ TAB: 9,
+ ENTER: 13,
+ ESCAPE: 27,
+ SPACE: 32,
+ PAGE_UP: 33,
+ PAGE_DOWN: 34,
+ END: 35,
+ HOME: 36,
+ LEFT: 37,
+ UP: 38,
+ RIGHT: 39,
+ DOWN: 40,
+ NUMPAD_ENTER: 108,
+ COMMA: 188
+};
+
+// Additional public (exposed) methods
+var methods = {
+ init: function(url_or_data_or_function, options) {
+ var settings = $.extend({}, DEFAULT_SETTINGS, options || {});
+
+ return this.each(function () {
+ $(this).data("tokenInputObject", new $.TokenList(this, url_or_data_or_function, settings));
+ });
+ },
+ clear: function() {
+ this.data("tokenInputObject").clear();
+ return this;
+ },
+ add: function(item) {
+ this.data("tokenInputObject").add(item);
+ return this;
+ },
+ remove: function(item) {
+ this.data("tokenInputObject").remove(item);
+ return this;
+ },
+ get: function() {
+ return this.data("tokenInputObject").getTokens();
+ }
+}
+
+// Expose the .tokenInput function to jQuery as a plugin
+$.fn.tokenInput = function (method) {
+ // Method calling and initialization logic
+ if(methods[method]) {
+ return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
+ } else {
+ return methods.init.apply(this, arguments);
+ }
+};
+
+// TokenList class for each input
+$.TokenList = function (input, url_or_data, settings) {
+ //
+ // Initialization
+ //
+
+ // Configure the data source
+ if($.type(url_or_data) === "string" || $.type(url_or_data) === "function") {
+ // Set the url to query against
+ settings.url = url_or_data;
+
+ // If the URL is a function, evaluate it here to do our initalization work
+ var url = computeURL();
+
+ // Make a smart guess about cross-domain if it wasn't explicitly specified
+ if(settings.crossDomain === undefined) {
+ if(url.indexOf("://") === -1) {
+ settings.crossDomain = false;
+ } else {
+ settings.crossDomain = (location.href.split(/\/+/g)[1] !== url.split(/\/+/g)[1]);
+ }
+ }
+ } else if(typeof(url_or_data) === "object") {
+ // Set the local data to search through
+ settings.local_data = url_or_data;
+ }
+
+ // Build class names
+ if(settings.classes) {
+ // Use custom class names
+ settings.classes = $.extend({}, DEFAULT_CLASSES, settings.classes);
+ } else if(settings.theme) {
+ // Use theme-suffixed default class names
+ settings.classes = {};
+ $.each(DEFAULT_CLASSES, function(key, value) {
+ settings.classes[key] = value + "-" + settings.theme;
+ });
+ } else {
+ settings.classes = DEFAULT_CLASSES;
+ }
+
+
+ // Save the tokens
+ var saved_tokens = [];
+
+ // Keep track of the number of tokens in the list
+ var token_count = 0;
+
+ // Basic cache to save on db hits
+ var cache = new $.TokenList.Cache();
+
+ // Keep track of the timeout, old vals
+ var timeout;
+ var input_val;
+
+ function tokenize(){
+ var item = $(selected_dropdown_item).data("tokeninput");
+ if(!item && settings.textToData){
+ item = settings.textToData(input_box.val());
+ }
+
+ if(item) {
+ add_token(item);
+ hidden_input.change();
+ return false;
+ }
+ }
+
+ // Create a new text input an attach keyup events
+ var input_box = $("<input type=\"text\" autocomplete=\"off\">")
+ .css({
+ outline: "none"
+ })
+ .attr("id", settings.idPrefix + input.id)
+ .focus(function () {
+ if (settings.minChars == 0) {
+ setTimeout(function(){do_search();}, 5);
+ }
+ if (settings.tokenLimit === null || settings.tokenLimit !== token_count) {
+ show_dropdown_hint();
+ }
+ })
+ .blur(function () {
+ tokenize();
+ hide_dropdown();
+ $(this).val("");
+ })
+ .bind("keyup keydown blur update", resize_input)
+ .keydown(function (event) {
+ var previous_token;
+ var next_token;
+
+ switch(event.keyCode) {
+ case KEY.LEFT:
+ case KEY.RIGHT:
+ case KEY.UP:
+ case KEY.DOWN:
+ if(!$(this).val()) {
+ previous_token = input_token.prev();
+ next_token = input_token.next();
+
+ if((previous_token.length && previous_token.get(0) === selected_token) || (next_token.length && next_token.get(0) === selected_token)) {
+ // Check if there is a previous/next token and it is selected
+ if(event.keyCode === KEY.LEFT || event.keyCode === KEY.UP) {
+ deselect_token($(selected_token), POSITION.BEFORE);
+ } else {
+ deselect_token($(selected_token), POSITION.AFTER);
+ }
+ } else if((event.keyCode === KEY.LEFT || event.keyCode === KEY.UP) && previous_token.length) {
+ // We are moving left, select the previous token if it exists
+ select_token($(previous_token.get(0)));
+ } else if((event.keyCode === KEY.RIGHT || event.keyCode === KEY.DOWN) && next_token.length) {
+ // We are moving right, select the next token if it exists
+ select_token($(next_token.get(0)));
+ }
+ } else {
+ if (event.keyCode === KEY.UP || event.keyCode === KEY.DOWN) {
+ var dropdown_item = null;
+ if(!selected_dropdown_item && (event.keyCode === KEY.DOWN)) {
+ dropdown_item = $('.token-input-dropdown li').first();
+ }
+ else if(event.keyCode === KEY.DOWN) {
+ dropdown_item = $(selected_dropdown_item).next();
+ } else {
+ dropdown_item = $(selected_dropdown_item).prev();
+ }
+
+ if(dropdown_item.length) {
+ select_dropdown_item(dropdown_item,true);
+ }
+ else if (!(event.keyCode === KEY.DOWN) && $(selected_dropdown_item).length) {
+ deselect_dropdown_item($(selected_dropdown_item));
+ }
+ return false;
+ }
+ }
+ break;
+
+ case KEY.BACKSPACE:
+ previous_token = input_token.prev();
+
+ if(!$(this).val().length) {
+ if(selected_token) {
+ delete_token($(selected_token));
+ hidden_input.change();
+ } else if(previous_token.length) {
+ select_token($(previous_token.get(0)));
+ }
+
+ return false;
+ } else if($(this).val().length === 1) {
+ hide_dropdown();
+ } else {
+ // set a timeout just long enough to let this function finish.
+ setTimeout(function(){do_search();}, 5);
+ }
+ break;
+
+ case KEY.TAB:
+ case KEY.ENTER:
+ case KEY.NUMPAD_ENTER:
+ case KEY.COMMA:
+ if (event.keyCode != KEY.ENTER && event.keyCode != KEY.NUMPAD_ENTER)
+ {
+ event.preventDefault();
+ }
+ tokenize();
+ break;
+
+ case KEY.ESCAPE:
+ hide_dropdown();
+ return true;
+
+ default:
+ if(String.fromCharCode(event.which)) {
+ // set a timeout just long enough to let this function finish.
+ setTimeout(function(){do_search();}, 5);
+ }
+ break;
+ }
+ });
+
+ // Keep a reference to the original input box
+ var hidden_input = $(input)
+ .hide()
+ .val("")
+ .focus(function () {
+ input_box.focus();
+ })
+ .blur(function () {
+ input_box.blur();
+ });
+
+ // Keep a reference to the selected token and dropdown item
+ var selected_token = null;
+ var selected_token_index = 0;
+ var selected_dropdown_item = null;
+
+ // The list to store the token items in
+ var token_list = $("<ul />")
+ .addClass(settings.classes.tokenList)
+ .click(function (event) {
+ var li = $(event.target).closest("li");
+ if(li && li.get(0) && $.data(li.get(0), "tokeninput")) {
+ toggle_select_token(li);
+ } else {
+ // Deselect selected token
+ if(selected_token) {
+ deselect_token($(selected_token), POSITION.END);
+ }
+
+ // Focus input box
+ input_box.focus();
+ }
+ })
+ .mouseover(function (event) {
+ var li = $(event.target).closest("li");
+ if(li && selected_token !== this) {
+ li.addClass(settings.classes.highlightedToken);
+ }
+ })
+ .mouseout(function (event) {
+ var li = $(event.target).closest("li");
+ if(li && selected_token !== this) {
+ li.removeClass(settings.classes.highlightedToken);
+ }
+ })
+ .insertBefore(hidden_input);
+
+ // The token holding the input box
+ var input_token = $("<li />")
+ .addClass(settings.classes.inputToken)
+ .appendTo(token_list)
+ .append(input_box);
+
+ // The list to store the dropdown items in
+ var dropdown = $("<div>")
+ .addClass(settings.classes.dropdown)
+ .appendTo("body")
+ .hide();
+
+ // Magic element to help us resize the text input
+ var input_resizer = $("<tester/>")
+ .insertAfter(input_box)
+ .css({
+ position: "absolute",
+ top: -9999,
+ left: -9999,
+ width: "auto",
+ fontSize: input_box.css("fontSize"),
+ fontFamily: input_box.css("fontFamily"),
+ fontWeight: input_box.css("fontWeight"),
+ letterSpacing: input_box.css("letterSpacing"),
+ whiteSpace: "nowrap"
+ });
+
+ // Pre-populate list if items exist
+ hidden_input.val("");
+ var li_data = settings.prePopulate || hidden_input.data("pre");
+ if(settings.processPrePopulate && $.isFunction(settings.onResult)) {
+ li_data = settings.onResult.call(hidden_input, li_data);
+ }
+ if(li_data && li_data.length) {
+ $.each(li_data, function (index, value) {
+ insert_token(value);
+ checkTokenLimit();
+ });
+ }
+
+ // Initialization is done
+ if($.isFunction(settings.onReady)) {
+ settings.onReady.call();
+ if (settings.minChars == 0)
+ {
+ setTimeout(function(){do_search();}, 5);
+ }
+ }
+
+ //
+ // Public functions
+ //
+
+ this.clear = function() {
+ token_list.children("li").each(function() {
+ if ($(this).children("input").length === 0) {
+ delete_token($(this));
+ }
+ });
+ }
+
+ this.add = function(item) {
+ add_token(item);
+ }
+
+ this.remove = function(item) {
+ token_list.children("li").each(function() {
+ if ($(this).children("input").length === 0) {
+ var currToken = $(this).data("tokeninput");
+ var match = true;
+ for (var prop in item) {
+ if (item[prop] !== currToken[prop]) {
+ match = false;
+ break;
+ }
+ }
+ if (match) {
+ delete_token($(this));
+ }
+ }
+ });
+ }
+
+ this.getTokens = function() {
+ return saved_tokens;
+ }
+
+ //
+ // Private functions
+ //
+
+ function checkTokenLimit() {
+ if(settings.tokenLimit !== null && token_count >= settings.tokenLimit) {
+ input_box.hide();
+ hide_dropdown();
+ return;
+ }
+ }
+
+ function resize_input() {
+ if(input_val === (input_val = input_box.val())) {return;}
+
+ // Enter new content into resizer and resize input accordingly
+ var escaped = input_val.replace(/&/g, '&amp;').replace(/\s/g,' ').replace(/</g, '&lt;').replace(/>/g, '&gt;');
+ input_resizer.html(escaped);
+ var minwidth = 30;
+ if (settings.emptyInputLength && token_list.children().length < 2) {
+ minwidth = settings.emptyInputLength;
+ }
+ input_box.width(input_resizer.width() + minwidth);
+ }
+
+ function is_printable_character(keycode) {
+ return ((keycode >= 48 && keycode <= 90) || // 0-1a-z
+ (keycode >= 96 && keycode <= 111) || // numpad 0-9 + - / * .
+ (keycode >= 186 && keycode <= 192) || // ; = , - . / ^
+ (keycode >= 219 && keycode <= 222)); // ( \ ) '
+ }
+
+ // Inner function to a token to the list
+ function insert_token(item) {
+ var this_token = settings.tokenFormatter(item);
+ this_token = $(this_token)
+ .addClass(settings.classes.token)
+ .insertBefore(input_token);
+
+ // The 'delete token' button
+ $("<span>" + settings.deleteText + "</span>")
+ .addClass(settings.classes.tokenDelete)
+ .appendTo(this_token)
+ .click(function () {
+ delete_token($(this).parent());
+ hidden_input.change();
+ return false;
+ });
+
+ // Store data on the token
+ var token_data = {"id": item.id};
+ token_data[settings.propertyToSearch] = item[settings.propertyToSearch];
+ token_data.item = item;
+ $.data(this_token.get(0), "tokeninput", item);
+
+ // Save this token for duplicate checking
+ saved_tokens = saved_tokens.slice(0,selected_token_index).concat([token_data]).concat(saved_tokens.slice(selected_token_index));
+ selected_token_index++;
+
+ // Update the hidden input
+ update_hidden_input(saved_tokens, hidden_input);
+
+ token_count += 1;
+
+ // Check the token limit
+ if(settings.tokenLimit !== null && token_count >= settings.tokenLimit) {
+ input_box.hide();
+ hide_dropdown();
+ }
+
+ return this_token;
+ }
+
+ // Add a token to the token list based on user input
+ function add_token (item) {
+ if(!item) return;
+
+ // Check for item validation
+ if ($.isFunction(settings.validateItem) && !settings.validateItem(item)) {
+ return false;
+ }
+
+ var callback = settings.onAdd;
+
+ // See if the token already exists and select it if we don't want duplicates
+ if(token_count > 0 && settings.preventDuplicates) {
+ var found_existing_token = null;
+ token_list.children().each(function () {
+ var existing_token = $(this);
+ var existing_data = $.data(existing_token.get(0), "tokeninput");
+ if(existing_data && existing_data.id === item.id) {
+ found_existing_token = existing_token;
+ return false;
+ }
+ });
+
+ if(found_existing_token) {
+ select_token(found_existing_token);
+ input_token.insertAfter(found_existing_token);
+ input_box.focus();
+ return;
+ }
+ }
+
+ // Insert the new tokens
+ if(settings.tokenLimit == null || token_count < settings.tokenLimit) {
+ insert_token(item);
+ checkTokenLimit();
+ }
+
+ // Clear input box
+ input_box.val("");
+
+ // Don't show the help dropdown, they've got the idea
+ hide_dropdown();
+
+ // Execute the onAdd callback if defined
+ if($.isFunction(callback)) {
+ callback.call(hidden_input,item);
+ }
+ }
+
+ // Select a token in the token list
+ function select_token (token) {
+ token.addClass(settings.classes.selectedToken);
+ selected_token = token.get(0);
+
+ // Hide input box
+ input_box.val("");
+
+ // Hide dropdown if it is visible (eg if we clicked to select token)
+ hide_dropdown();
+ }
+
+ // Deselect a token in the token list
+ function deselect_token (token, position) {
+ token.removeClass(settings.classes.selectedToken);
+ selected_token = null;
+
+ if(position === POSITION.BEFORE) {
+ input_token.insertBefore(token);
+ selected_token_index--;
+ } else if(position === POSITION.AFTER) {
+ input_token.insertAfter(token);
+ selected_token_index++;
+ } else {
+ input_token.appendTo(token_list);
+ selected_token_index = token_count;
+ }
+
+ // Show the input box and give it focus again
+ input_box.focus();
+ }
+
+ // Toggle selection of a token in the token list
+ function toggle_select_token(token) {
+ var previous_selected_token = selected_token;
+
+ if(selected_token) {
+ deselect_token($(selected_token), POSITION.END);
+ }
+
+ if(previous_selected_token === token.get(0)) {
+ deselect_token(token, POSITION.END);
+ } else {
+ select_token(token);
+ }
+ }
+
+ // Delete a token from the token list
+ function delete_token (token) {
+ // Remove the id from the saved list
+ var token_data = $.data(token.get(0), "tokeninput");
+ var callback = settings.onDelete;
+
+ var index = token.prevAll().length;
+ if(index > selected_token_index) index--;
+
+ // Delete the token
+ token.remove();
+ selected_token = null;
+
+ // Show the input box and give it focus again
+ input_box.focus();
+
+ // Remove this token from the saved list
+ saved_tokens = saved_tokens.slice(0,index).concat(saved_tokens.slice(index+1));
+ if(index < selected_token_index) selected_token_index--;
+
+ // Update the hidden input
+ update_hidden_input(saved_tokens, hidden_input);
+
+ token_count -= 1;
+
+ if(settings.tokenLimit !== null) {
+ input_box
+ .show()
+ .val("")
+ .focus();
+ }
+
+ // Execute the onDelete callback if defined
+ if($.isFunction(callback)) {
+ callback.call(hidden_input,token_data);
+ }
+ }
+
+ // Update the hidden input box value
+ function update_hidden_input(saved_tokens, hidden_input) {
+ var token_values = $.map(saved_tokens, function (el) {
+ return el[settings.tokenValue];
+ });
+ hidden_input.val(token_values.join(settings.tokenDelimiter));
+
+ }
+
+ // Hide and clear the results dropdown
+ function hide_dropdown () {
+ dropdown.hide().empty();
+ selected_dropdown_item = null;
+ if (settings.onHideDropdown)
+ settings.onHideDropdown();
+ }
+
+ function show_dropdown() {
+ dropdown
+ .css({
+ position: "absolute",
+ top: $(token_list).offset().top + $(token_list).outerHeight(),
+ left: $(token_list).offset().left,
+ zindex: 999
+ })
+ .show();
+ if (settings.onShowDropdown)
+ settings.onShowDropdown();
+ }
+
+ function show_dropdown_searching () {
+ if(settings.searchingText) {
+ dropdown.html("<p>"+settings.searchingText+"</p>");
+ show_dropdown();
+ }
+ }
+
+ function show_dropdown_hint () {
+ if(settings.hintText) {
+ dropdown.html("<p>"+settings.hintText+"</p>");
+ show_dropdown();
+ }
+ }
+
+ // Highlight the query part of the search term
+ function highlight_term(value, term) {
+ return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<b>$1</b>");
+ }
+
+ function find_value_and_highlight_term(template, value, term) {
+ return template.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + value + ")(?![^<>]*>)(?![^&;]+;)", "g"), highlight_term(value, term));
+ }
+
+ // Populate the results dropdown with some results
+ function populate_dropdown (query, results) {
+ if(results && results.length) {
+ dropdown.empty();
+ var dropdown_ul = $("<ul>")
+ .appendTo(dropdown)
+ .mouseover(function (event) {
+ select_dropdown_item($(event.target).closest("li"));
+ })
+ .mousedown(function (event) {
+ add_token($(event.target).closest("li").data("tokeninput"));
+ hidden_input.change();
+ return false;
+ })
+ .hide();
+ if (settings.noHoverSelect) {
+ dropdown_ul.off('mouseover');
+ dropdown_ul.on('mouseover',function (event) {
+ $(this).find("li").removeClass(settings.classes.selectedDropdownItem);
+ $(event.target).closest("li").addClass(settings.classes.selectedDropdownItem);
+ });
+ }
+
+ $.each(results, function(index, value) {
+ var this_li = settings.resultsFormatter(value);
+
+ // this_li = find_value_and_highlight_term(this_li ,value[settings.propertyToSearch], query);
+
+ this_li = $(this_li).appendTo(dropdown_ul);
+
+ if(index % 2) {
+ this_li.addClass(settings.classes.dropdownItem);
+ } else {
+ this_li.addClass(settings.classes.dropdownItem2);
+ }
+
+ // if(index === 0) {
+ // select_dropdown_item(this_li);
+ // }
+
+ $.data(this_li.get(0), "tokeninput", value);
+ });
+
+ show_dropdown();
+
+ if(settings.animateDropdown) {
+ dropdown_ul.slideDown("fast");
+ } else {
+ dropdown_ul.show();
+ }
+ } else {
+ if(settings.noResultsText) {
+ dropdown.html("<p>"+settings.noResultsText+"</p>");
+ show_dropdown();
+ }
+ if (settings.noResultsHideDropdown) {
+ hide_dropdown();
+ }
+ }
+ }
+
+ // Highlight an item in the results dropdown
+ function select_dropdown_item (item,withkeyboard) {
+ if(item) {
+ if(selected_dropdown_item) {
+ deselect_dropdown_item($(selected_dropdown_item));
+ }
+ if (settings.scrollKeyboard && withkeyboard) {
+ var list = $('.token-input-dropdown-tag ul');
+ var listheight = list.height();
+ var itemheight = item.outerHeight();
+ var itemtop = item.position().top;
+ if (itemtop > listheight) {
+ var listscroll = list.scrollTop();
+ list.scrollTop(listscroll + itemheight);
+ }
+ else if (itemtop < 0) {
+ var listscroll = list.scrollTop();
+ list.scrollTop(listscroll - itemheight);
+ }
+
+ }
+ item.addClass(settings.classes.selectedDropdownItem);
+ selected_dropdown_item = item.get(0);
+ }
+ }
+
+ // Remove highlighting from an item in the results dropdown
+ function deselect_dropdown_item (item) {
+ item.removeClass(settings.classes.selectedDropdownItem);
+ selected_dropdown_item = null;
+ }
+
+ // Do a search and show the "searching" dropdown if the input is longer
+ // than settings.minChars
+ function do_search() {
+ var query = input_box.val().toLowerCase();
+ if(query && query.length || settings.minChars == 0) {
+ if(selected_token) {
+ deselect_token($(selected_token), POSITION.AFTER);
+ }
+
+ if(query.length >= settings.minChars) {
+ show_dropdown_searching();
+ clearTimeout(timeout);
+
+ timeout = setTimeout(function(){
+ run_search(query);
+ }, settings.searchDelay);
+ } else {
+ hide_dropdown();
+ }
+ }
+ }
+
+ // Do the actual search
+ function run_search(query) {
+ var cache_key = query + computeURL();
+ var cached_results = cache.get(cache_key);
+ if(cached_results) {
+ populate_dropdown(query, cached_results);
+ } else {
+ // Are we doing an ajax search or local data search?
+ if(settings.url) {
+ var url = computeURL();
+ // Extract exisiting get params
+ var ajax_params = {};
+ ajax_params.data = {};
+ if(url.indexOf("?") > -1) {
+ var parts = url.split("?");
+ ajax_params.url = parts[0];
+
+ var param_array = parts[1].split("&");
+ $.each(param_array, function (index, value) {
+ var kv = value.split("=");
+ ajax_params.data[kv[0]] = kv[1];
+ });
+ } else {
+ ajax_params.url = url;
+ }
+
+ // Prepare the request
+ ajax_params.data[settings.queryParam] = query;
+ ajax_params.type = settings.method;
+ ajax_params.dataType = settings.contentType;
+ if(settings.crossDomain) {
+ ajax_params.dataType = "jsonp";
+ }
+
+ // Attach the success callback
+ ajax_params.success = function(results) {
+ if($.isFunction(settings.onResult)) {
+ results = settings.onResult.call(hidden_input, results);
+ }
+ cache.add(cache_key, settings.jsonContainer ? results[settings.jsonContainer] : results);
+
+ // only populate the dropdown if the results are associated with the active search query
+ if(input_box.val().toLowerCase() === query) {
+ populate_dropdown(query, settings.jsonContainer ? results[settings.jsonContainer] : results);
+ }
+ };
+
+ // Make the request
+ $.ajax(ajax_params);
+ } else if(settings.search_function){
+ settings.search_function(query, function(results){
+ cache.add(cache_key, results);
+ populate_dropdown(query, results);
+ });
+ } else if(settings.local_data) {
+ // Do the search through local data
+ var results = $.grep(settings.local_data, function (row) {
+ return row[settings.propertyToSearch].toLowerCase().indexOf(query.toLowerCase()) > -1;
+ });
+
+ if($.isFunction(settings.onResult)) {
+ results = settings.onResult.call(hidden_input, results);
+ }
+ cache.add(cache_key, results);
+ populate_dropdown(query, results);
+ }
+ }
+ }
+
+ // compute the dynamic URL
+ function computeURL() {
+ var url = settings.url;
+ if(typeof settings.url == 'function') {
+ url = settings.url.call();
+ }
+ return url;
+ }
+};
+
+// Really basic cache for the results
+$.TokenList.Cache = function (options) {
+ var settings = $.extend({
+ max_size: 500
+ }, options);
+
+ var data = {};
+ var size = 0;
+
+ var flush = function () {
+ data = {};
+ size = 0;
+ };
+
+ this.add = function (query, results) {
+ if(size > settings.max_size) {
+ flush();
+ }
+
+ if(!data[query]) {
+ size += 1;
+ }
+
+ data[query] = results;
+ };
+
+ this.get = function (query) {
+ return data[query];
+ };
+};
+}(jQuery));
diff --git a/browser/extensions/pocket/content/panels/license.txt b/browser/extensions/pocket/content/panels/license.txt
new file mode 100644
index 000000000..7f3f806ba
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/license.txt
@@ -0,0 +1,35 @@
+
+Unless where otherwise noted, the following license applies to the files
+within this directory and descendents of this directory.
+
+POCKET MARKS
+
+Notwithstanding the permitted uses of the Software (as defined below) pursuant
+to the license set forth below, "Pocket," "Read It Later" and the Pocket icon
+and logos (collectively, the “Pocket Marks”) are registered and common law
+trademarks of Read It Later, Inc. This means that, while you have considerable
+freedom to redistribute and modify the Software, there are tight restrictions
+on your ability to use the Pocket Marks. This license does not grant you any
+rights to use the Pocket Marks except as they are embodied in the Software.
+
+---
+
+SOFTWARE
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/browser/extensions/pocket/content/panels/saved.html b/browser/extensions/pocket/content/panels/saved.html
new file mode 100644
index 000000000..93477d8ee
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/saved.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <base href="chrome://pocket/content/panels/">
+ <title>Pocket: Page Saved</title>
+ <link rel="stylesheet" href="css/normalize.css">
+ <link rel="stylesheet" href="css/firasans.css">
+ <link rel="stylesheet" href="css/saved.css">
+ </head>
+ <body class="pkt_ext_containersaved" aria-live="polite">
+ <script type="text/javascript" src="js/vendor/jquery-2.1.1.min.js"></script>
+ <script type="text/javascript" src="js/vendor/handlebars.runtime.js"></script>
+ <script type="text/javascript" src="js/vendor/jquery.tokeninput.min.js"></script>
+ <script type="text/javascript" src="js/tmpl.js"></script>
+ <script type="text/javascript" src="js/messages.js"></script>
+ <script type="text/javascript" src="js/saved.js"></script>
+ </body>
+</html>
diff --git a/browser/extensions/pocket/content/panels/signup.html b/browser/extensions/pocket/content/panels/signup.html
new file mode 100644
index 000000000..bcdf66ed4
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/signup.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <base href="chrome://pocket/content/panels/">
+ <title>Pocket: Sign Up</title>
+ <link rel="stylesheet" href="css/normalize.css">
+ <link rel="stylesheet" href="css/firasans.css">
+ <link rel="stylesheet" href="css/signup.css">
+ </head>
+ <body class="pkt_ext_containersignup" aria-live="polite">
+ <script type="text/javascript" src="js/vendor/jquery-2.1.1.min.js"></script>
+ <script type="text/javascript" src="js/vendor/handlebars.runtime.js"></script>
+ <script type="text/javascript" src="js/tmpl.js"></script>
+ <script type="text/javascript" src="js/messages.js"></script>
+ <script type="text/javascript" src="js/signup.js"></script>
+ </body>
+</html>
diff --git a/browser/extensions/pocket/content/panels/tmpl/saved_premiumextras.handlebars b/browser/extensions/pocket/content/panels/tmpl/saved_premiumextras.handlebars
new file mode 100644
index 000000000..b224450ec
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/tmpl/saved_premiumextras.handlebars
@@ -0,0 +1,2 @@
+<div class="pkt_ext_suggestedtag_detailshown">
+</div> \ No newline at end of file
diff --git a/browser/extensions/pocket/content/panels/tmpl/saved_premiumshell.handlebars b/browser/extensions/pocket/content/panels/tmpl/saved_premiumshell.handlebars
new file mode 100644
index 000000000..5ef042636
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/tmpl/saved_premiumshell.handlebars
@@ -0,0 +1,6 @@
+<div class="pkt_ext_suggestedtag_detail pkt_ext_suggestedtag_detail_loading">
+ <h4>{{suggestedtags}}</h4>
+ <div class="pkt_ext_loadingspinner"><div></div></div>
+ <ul class="pkt_ext_cf">
+ </ul>
+</div> \ No newline at end of file
diff --git a/browser/extensions/pocket/content/panels/tmpl/saved_shell.handlebars b/browser/extensions/pocket/content/panels/tmpl/saved_shell.handlebars
new file mode 100644
index 000000000..89b7500cd
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/tmpl/saved_shell.handlebars
@@ -0,0 +1,29 @@
+<div class="pkt_ext_initload">
+ <div class="pkt_ext_logo"></div>
+ <div class="pkt_ext_topdetail">
+ <h2>{{saving}}</h2>
+ </div>
+ <div class="pkt_ext_loadingspinner"><div></div></div>
+</div>
+<div class="pkt_ext_detail">
+ <div class="pkt_ext_logo"></div>
+ <div class="pkt_ext_topdetail">
+ <h2>{{pagesaved}}</h2>
+ <h3 class="pkt_ext_errordetail"></h3>
+ <nav class="pkt_ext_item_actions pkt_ext_cf">
+ <ul>
+ <li><a class="pkt_ext_removeitem" href="#">{{removepage}}</a></li>
+ <li class="pkt_ext_actions_separator"></li>
+ <li><a class="pkt_ext_openpocket" href="https://{{pockethost}}/a?src=ff_ext_saved" target="_blank">{{viewlist}}</a></li>
+ </ul>
+ </nav>
+ </div>
+ <div class="pkt_ext_tag_detail pkt_ext_cf">
+ <div class="pkt_ext_tag_input_wrapper">
+ <div class="pkt_ext_tag_input_blocker"></div>
+ <input class="pkt_ext_tag_input" type="text" placeholder="{{addtags}}">
+ </div>
+ <a href="#" class="pkt_ext_btn pkt_ext_btn_disabled">{{save}}</a>
+ </div>
+ <p class="pkt_ext_edit_msg"></p>
+</div> \ No newline at end of file
diff --git a/browser/extensions/pocket/content/panels/tmpl/signup_shell.handlebars b/browser/extensions/pocket/content/panels/tmpl/signup_shell.handlebars
new file mode 100644
index 000000000..8dddaef60
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/tmpl/signup_shell.handlebars
@@ -0,0 +1,32 @@
+<div class="pkt_ext_introdetail pkt_ext_introdetailhero">
+ <h2 class="pkt_ext_logo">Pocket</h2>
+ <p class="pkt_ext_tagline">{{tagline}}</p>
+ {{#if showlearnmore}}
+ {{#if controlvariant}}
+ <p class="pkt_ext_learnmorecontainer"><a class="pkt_ext_learnmore" href="https://{{pockethost}}/firefox_learnmore?s=ffi&t=learnmore&tv=panel_control&v={{variant}}" target="_blank">{{learnmore}}</a></p>
+ {{else}}
+ <p class="pkt_ext_learnmorecontainer"><a class="pkt_ext_learnmore" href="https://{{pockethost}}/firefox_learnmore?s=ffi&t=learnmore&tv=panel_tryit&v={{variant}}" target="_blank">{{learnmore}}</a></p>
+ {{/if}}
+ {{else}}
+ <p class="pkt_ext_learnmorecontainer"><a class="pkt_ext_learnmore pkt_ext_learnmoreinactive" href="#">{{learnmore}}</a></p>
+ {{/if}}
+ <div class="pkt_ext_introimg"></div>
+</div>
+<div class="pkt_ext_signupdetail pkt_ext_signupdetail_hero">
+ {{#if fxasignedin}}
+ <h4>{{signuptosave}}</h4>
+ <p class="btn-container"><a href="https://{{pockethost}}/ff_signup?s=ffi&t=signupff&v={{variant}}" target="_blank" class="btn signup-btn-firefox"><span class="logo"></span><span class="text">{{signinfirefox}}</span></a></p>
+ <p class="alreadyhave">{{alreadyhaveacct}} <a href="https://{{pockethost}}/login?ep=3&src=extension&s=ffi&t=login&v={{variant}}" target="_blank">{{loginnow}}</a>.</p>
+ {{else}}
+ {{#if controlvariant}}
+ <h4>{{signuptosave}}</h4>
+ <p class="btn-container"><a href="https://{{pockethost}}/ff_signup?s=ffi&tv=panel_control&t=signupff&v={{variant}}" target="_blank" class="btn signup-btn-firefox"><span class="logo"></span><span class="text">{{signupfirefox}}</span></a></p>
+ <p class="btn-container"><a href="https://{{pockethost}}/signup?force=email&tv=panel_control&src=extension&s=ffi&t=signupemail&v={{variant}}" target="_blank" class="btn btn-secondary signup-btn-email signup-btn-initstate">{{signupemail}}</a></p>
+ <p class="alreadyhave">{{alreadyhaveacct}} <a href="https://{{pockethost}}/login?ep=3&tv=panel_control&src=extension&s=ffi&t=login&v={{variant}}" target="_blank">{{loginnow}}</a>.</p>
+ {{else}}
+ <p class="btn-container"><a href="https://{{pockethost}}/firefox_tryitnow?s=ffi&tv=panel_tryit&t=tryitnow" target="_blank" class="btn signup-btn-tryitnow"><span class="text">{{tryitnow}}</span></a></p>
+ <p class="alreadyhave tryitnowspace">{{alreadyhaveacct}} <a href="https://{{pockethost}}/login?ep=3&s=ffi&tv=panel_tryit&src=extension&t=login&v={{variant}}" target="_blank">{{loginnow}}</a>.</p>
+ <p class="pkt_ext_tos">{{{tos}}}</p>
+ {{/if}}
+ {{/if}}
+</div>
diff --git a/browser/extensions/pocket/content/panels/tmpl/signupstoryboard_shell.handlebars b/browser/extensions/pocket/content/panels/tmpl/signupstoryboard_shell.handlebars
new file mode 100644
index 000000000..8a181e23d
--- /dev/null
+++ b/browser/extensions/pocket/content/panels/tmpl/signupstoryboard_shell.handlebars
@@ -0,0 +1,43 @@
+<div class="pkt_ext_introdetail pkt_ext_introdetailstoryboard">
+ <div class="pkt_ext_introstory pkt_ext_introstoryone">
+ <div class="pkt_ext_introstory_text">
+ <p class="pkt_ext_tagline">{{taglinestory_one}}</p>
+ </div>
+ <div class="pkt_ext_introstoryone_img"></div>
+ </div>
+ <div class="pkt_ext_introstorydivider"></div>
+ <div class="pkt_ext_introstory pkt_ext_introstorytwo">
+ <div class="pkt_ext_introstory_text">
+ <p class="pkt_ext_tagline">{{taglinestory_two}}</p>
+ {{#if showlearnmore}}
+ {{#if controlvariant}}
+ <p><a class="pkt_ext_learnmore" href="https://{{pockethost}}/firefox_learnmore?s=ffi&t=learnmore&tv=panel_control&v={{variant}}" target="_blank">{{learnmore}}</a></p>
+ {{else}}
+ <p><a class="pkt_ext_learnmore" href="https://{{pockethost}}/firefox_learnmore?s=ffi&t=learnmore&tv=panel_tryit&v={{variant}}" target="_blank">{{learnmore}}</a></p>
+ {{/if}}
+ {{else}}
+ <p><a class="pkt_ext_learnmore pkt_ext_learnmoreinactive" href="#">{{learnmore}}</a></p>
+ {{/if}}
+ </div>
+ <div class="pkt_ext_introstorytwo_img"></div>
+ </div>
+</div>
+<div class="pkt_ext_signupdetail">
+ {{#if fxasignedin}}
+ <h4>{{signuptosave}}</h4>
+ <p class="btn-container"><a href="https://{{pockethost}}/ff_signup?s=ffi&t=signupff&v={{variant}}" target="_blank" class="btn signup-btn-firefox"><span class="logo"></span><span class="text">{{signinfirefox}}</span></a></p>
+ <p class="alreadyhave">{{alreadyhaveacct}} <a href="https://{{pockethost}}/login?ep=3&src=extension&s=ffi&t=login&v={{variant}}" target="_blank">{{loginnow}}</a>.</p>
+ {{else}}
+ {{#if controlvariant}}
+ <h4>{{signuptosave}}</h4>
+ <p class="btn-container"><a href="https://{{pockethost}}/ff_signup?s=ffi&tv=panel_control&t=signupff&v={{variant}}" target="_blank" class="btn signup-btn-firefox"><span class="logo"></span><span class="text">{{signupfirefox}}</span></a></p>
+ <p class="btn-container"><a href="https://{{pockethost}}/signup?force=email&tv=panel_control&src=extension&s=ffi&t=signupemail&v={{variant}}" target="_blank" class="btn btn-secondary signup-btn-email signup-btn-initstate">{{signupemail}}</a></p>
+ <p class="alreadyhave">{{alreadyhaveacct}} <a href="https://{{pockethost}}/login?ep=3&tv=panel_control&src=extension&s=ffi&t=login&v={{variant}}" target="_blank">{{loginnow}}</a>.</p>
+ {{else}}
+ <p class="btn-container"><a href="https://{{pockethost}}/firefox_tryitnow?s=ffi&tv=panel_tryit&t=tryitnow" target="_blank" class="btn signup-btn-tryitnow"><span class="text">{{tryitnow}}</span></a></p>
+ <p class="alreadyhave tryitnowspace">{{alreadyhaveacct}} <a href="https://{{pockethost}}/login?ep=3&s=ffi&tv=panel_tryit&src=extension&t=login&v={{variant}}" target="_blank">{{loginnow}}</a>.</p>
+ <p class="pkt_ext_tos">{{{tos}}}</p>
+ {{/if}}
+ {{/if}}
+
+</div>
diff --git a/browser/extensions/pocket/content/pktApi.jsm b/browser/extensions/pocket/content/pktApi.jsm
new file mode 100644
index 000000000..63b6d415c
--- /dev/null
+++ b/browser/extensions/pocket/content/pktApi.jsm
@@ -0,0 +1,657 @@
+/*
+ * LICENSE
+ *
+ * POCKET MARKS
+ *
+ * Notwithstanding the permitted uses of the Software (as defined below) pursuant to the license set forth below, "Pocket," "Read It Later" and the Pocket icon and logos (collectively, the “Pocket Marks”) are registered and common law trademarks of Read It Later, Inc. This means that, while you have considerable freedom to redistribute and modify the Software, there are tight restrictions on your ability to use the Pocket Marks. This license does not grant you any rights to use the Pocket Marks except as they are embodied in the Software.
+ *
+ * ---
+ *
+ * SOFTWARE
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/*
+ * Pocket API module
+ *
+ * Public API Documentation: http://getpocket.com/developer/
+ *
+ *
+ * Definition of keys stored in preferences to preserve user state:
+ * premium_status: Current premium status for logged in user if available
+ * Can be 0 for no premium and 1 for premium
+ * latestSince: Last timestamp a save happened
+ * tags: All tags for logged in user
+ * usedTags: All used tags from within the extension sorted by recency
+ */
+
+const {classes: Cc, interfaces: Ci, utils: Cu, manager: Cm} = Components;
+this.EXPORTED_SYMBOLS = ["pktApi"];
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+
+var pktApi = (function() {
+
+ /**
+ * Configuration
+ */
+
+ // Base url for all api calls
+ var pocketAPIhost = Services.prefs.getCharPref("extensions.pocket.api"); // api.getpocket.com
+ var pocketSiteHost = Services.prefs.getCharPref("extensions.pocket.site"); // getpocket.com
+ var baseAPIUrl = "https://" + pocketAPIhost + "/v3";
+
+
+ /**
+ * Auth keys for the API requests
+ */
+ var oAuthConsumerKey = Services.prefs.getCharPref("extensions.pocket.oAuthConsumerKey");
+
+ /**
+ *
+ */
+ var prefBranch = Services.prefs.getBranch("extensions.pocket.settings.");
+
+ /**
+ * Helper
+ */
+
+ var extend = function(out) {
+ out = out || {};
+
+ for (var i = 1; i < arguments.length; i++) {
+ if (!arguments[i])
+ continue;
+
+ for (var key in arguments[i]) {
+ if (arguments[i].hasOwnProperty(key))
+ out[key] = arguments[i][key];
+ }
+ }
+ return out;
+ }
+
+ var parseJSON = function(jsonString) {
+ try {
+ var o = JSON.parse(jsonString);
+
+ // Handle non-exception-throwing cases:
+ // Neither JSON.parse(false) or JSON.parse(1234) throw errors, hence the type-checking,
+ // but... JSON.parse(null) returns 'null', and typeof null === "object",
+ // so we must check for that, too.
+ if (o && typeof o === "object" && o !== null) {
+ return o;
+ }
+ }
+ catch (e) { }
+
+ return undefined;
+ };
+
+ /**
+ * Settings
+ */
+
+ /**
+ * Wrapper for different plattforms to get settings for a given key
+ * @param {string} key A string containing the name of the key you want to
+ * retrieve the value of
+ * @return {string} String containing the value of the key. If the key
+ * does not exist, null is returned
+ */
+ function getSetting(key) {
+ // TODO : Move this to sqlite or a local file so it's not editable (and is safer)
+ // https://developer.mozilla.org/en-US/Add-ons/Overlay_Extensions/XUL_School/Local_Storage
+
+ if (!prefBranch.prefHasUserValue(key))
+ return undefined;
+
+ return prefBranch.getComplexValue(key, Components.interfaces.nsISupportsString).data;
+ }
+
+ /**
+ * Wrapper for different plattforms to set a value for a given key in settings
+ * @param {string} key A string containing the name of the key you want
+ * to create/update.
+ * @param {string} value String containing the value you want to give
+ * the key you are creating/updating.
+ */
+ function setSetting(key, value) {
+ // TODO : Move this to sqlite or a local file so it's not editable (and is safer)
+ // https://developer.mozilla.org/en-US/Add-ons/Overlay_Extensions/XUL_School/Local_Storage
+
+ if (!value)
+ prefBranch.clearUserPref(key);
+ else
+ {
+ // We use complexValue as tags can have utf-8 characters in them
+ var str = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString);
+ str.data = value;
+ prefBranch.setComplexValue(key, Components.interfaces.nsISupportsString, str);
+ }
+ }
+
+ /**
+ * Auth
+ */
+
+ /*
+ * All cookies from the Pocket domain
+ * The return format: { cookieName:cookieValue, cookieName:cookieValue, ... }
+ */
+ function getCookiesFromPocket() {
+
+ var cookieManager = Cc["@mozilla.org/cookiemanager;1"].getService(Ci.nsICookieManager2);
+ var pocketCookies = cookieManager.getCookiesFromHost(pocketSiteHost, {});
+ var cookies = {};
+ while (pocketCookies.hasMoreElements()) {
+ var cookie = pocketCookies.getNext().QueryInterface(Ci.nsICookie2);
+ cookies[cookie.name] = cookie.value;
+ }
+ return cookies;
+ }
+
+ /**
+ * Returns access token or undefined if no logged in user was found
+ * @return {string | undefined} Access token for logged in user user
+ */
+ function getAccessToken() {
+ var pocketCookies = getCookiesFromPocket();
+
+ // If no cookie was found just return undefined
+ if (typeof pocketCookies['ftv1'] === "undefined") {
+ return undefined;
+ }
+
+ // Check if a new user logged in in the meantime and clearUserData if so
+ var sessionId = pocketCookies['fsv1'];
+ var lastSessionId = getSetting('fsv1');
+ if (sessionId !== lastSessionId) {
+ clearUserData();
+ setSetting("fsv1", sessionId);
+ }
+
+ // Return access token
+ return pocketCookies['ftv1'];
+ }
+
+ /**
+ * Get the current premium status of the user
+ * @return {number | undefined} Premium status of user
+ */
+ function getPremiumStatus() {
+ var premiumStatus = getSetting("premium_status");
+ if (typeof premiumStatus === "undefined") {
+ // Premium status is not in settings try get it from cookie
+ var pocketCookies = getCookiesFromPocket();
+ premiumStatus = pocketCookies['ps'];
+ }
+ return premiumStatus;
+ }
+
+ /**
+ * Helper method to check if a user is premium or not
+ * @return {Boolean} Boolean if user is premium or not
+ */
+ function isPremiumUser() {
+ return getPremiumStatus() == 1;
+ }
+
+
+ /**
+ * Returns users logged in status
+ * @return {Boolean} Users logged in status
+ */
+ function isUserLoggedIn() {
+ return (typeof getAccessToken() !== "undefined");
+ }
+
+ /**
+ * API
+ */
+
+ /**
+ * Helper function for executing api requests. It mainly configures the
+ * ajax call with default values like type, headers or dataType for an api call.
+ * This function is for internal usage only.
+ * @param {Object} options
+ * Possible keys:
+ * - {string} path: This should be the Pocket API
+ * endpoint to call. For example providing the path
+ * "/get" would result in a call to getpocket.com/v3/get
+ * - {Object|undefined} data: Gets passed on to the jQuery ajax
+ * call as data parameter
+ * - {function(Object data, XMLHttpRequest xhr) | undefined} success:
+ * A function to be called if the request succeeds.
+ * - {function(Error errorThrown, XMLHttpRequest xhr) | undefined} error:
+ * A function to be called if the request fails.
+ * @return {Boolean} Returns Boolean whether the api call started sucessfully
+ *
+ */
+ function apiRequest(options) {
+ if ((typeof options === "undefined") || (typeof options.path === "undefined")) {
+ return false;
+ }
+
+ var url = baseAPIUrl + options.path;
+ var data = options.data || {};
+ data.locale_lang = Cc["@mozilla.org/chrome/chrome-registry;1"].
+ getService(Ci.nsIXULChromeRegistry).
+ getSelectedLocale("browser");
+ data.consumer_key = oAuthConsumerKey;
+
+ var request = Components.classes["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Components.interfaces.nsIXMLHttpRequest);
+ request.open("POST", url, true);
+ request.onreadystatechange = function(e) {
+ if (request.readyState == 4) {
+ if (request.status === 200) {
+ // There could still be an error if the response is no valid json
+ // or does not have status = 1
+ var response = parseJSON(request.response);
+ if (options.success && response && response.status == 1) {
+ options.success(response, request);
+ return;
+ }
+ }
+
+ // Handle error case
+ if (options.error) {
+ // In case the user did revoke the access token or it's not
+ // valid anymore clear the user data
+ if (request.status === 401) {
+ clearUserData();
+ }
+
+ // Handle error message
+ var errorMessage;
+ if (request.status !== 200) {
+ errorMessage = request.getResponseHeader("X-Error") || request.statusText;
+ errorMessage = JSON.parse('"' + errorMessage + '"');
+ }
+ var error = {message: errorMessage};
+ options.error(error, request);
+ }
+ }
+ };
+
+ // Set headers
+ request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
+ request.setRequestHeader('X-Accept', ' application/json');
+
+ // Serialize and Fire off the request
+ var str = [];
+ for (var p in data) {
+ if (data.hasOwnProperty(p)) {
+ str.push(encodeURIComponent(p) + "=" + encodeURIComponent(data[p]));
+ }
+ }
+
+ request.send(str.join("&"));
+
+ return true;
+ }
+
+ /**
+ * Cleans all settings for the previously logged in user
+ */
+ function clearUserData() {
+ // Clear stored information
+ setSetting("premium_status", undefined);
+ setSetting("latestSince", undefined);
+ setSetting("tags", undefined);
+ setSetting("usedTags", undefined);
+
+ setSetting("fsv1", undefined);
+ }
+
+ /**
+ * Add a new link to Pocket
+ * @param {string} url URL of the link
+ * @param {Object | undefined} options Can provide a string-based title, a
+ * `success` callback and an `error` callback.
+ * @return {Boolean} Returns Boolean whether the api call started sucessfully
+ */
+ function addLink(url, options) {
+
+ var since = getSetting('latestSince');
+ var accessToken = getAccessToken();
+
+ var sendData = {
+ access_token: accessToken,
+ url: url,
+ since: since ? since : 0
+ };
+
+ if (options.title) {
+ sendData.title = options.title;
+ }
+
+ return apiRequest({
+ path: "/firefox/save",
+ data: sendData,
+ success: function(data) {
+
+ // Update premium status, tags and since
+ var tags = data.tags;
+ if ((typeof tags !== "undefined") && Array.isArray(tags)) {
+ // If a tagslist is in the response replace the tags
+ setSetting('tags', JSON.stringify(data.tags));
+ }
+
+ // Update premium status
+ var premiumStatus = data.premium_status;
+ if (typeof premiumStatus !== "undefined") {
+ // If a premium_status is in the response replace the premium_status
+ setSetting("premium_status", premiumStatus);
+ }
+
+ // Save since value for further requests
+ setSetting('latestSince', data.since);
+
+ if (options.success) {
+ options.success.apply(options, Array.apply(null, arguments));
+ }
+ },
+ error: options.error
+ });
+ }
+
+ /**
+ * Delete an item identified by item id from the users list
+ * @param {string} itemId The id from the item we want to remove
+ * @param {Object | undefined} options Can provide an actionInfo object with
+ * further data to send to the API. Can
+ * have success and error callbacks
+ * @return {Boolean} Returns Boolean whether the api call started sucessfully
+ */
+ function deleteItem(itemId, options) {
+ var action = {
+ action: "delete",
+ item_id: itemId
+ };
+ return sendAction(action, options);
+ }
+
+ /**
+ * General function to send all kinds of actions like adding of links or
+ * removing of items via the API
+ * @param {Object} action Action object
+ * @param {Object | undefined} options Can provide an actionInfo object
+ * with further data to send to the
+ * API. Can have success and error
+ * callbacks
+ * @return {Boolean} Returns Boolean whether the api call started sucessfully
+ */
+ function sendAction(action, options) {
+ // Options can have an 'actionInfo' object. This actionInfo object gets
+ // passed through to the action object that will be send to the API endpoint
+ if (typeof options.actionInfo !== 'undefined') {
+ action = extend(action, options.actionInfo);
+ }
+ return sendActions([action], options);
+ }
+
+ /**
+ * General function to send all kinds of actions like adding of links or
+ * removing of items via the API
+ * @param {Array} actions Array of action objects
+ * @param {Object | undefined} options Can have success and error callbacks
+ * @return {Boolean} Returns Boolean whether the api call started sucessfully
+ */
+ function sendActions(actions, options) {
+ return apiRequest({
+ path: "/send",
+ data: {
+ access_token: getAccessToken(),
+ actions: JSON.stringify(actions)
+ },
+ success: options.success,
+ error: options.error
+ });
+ }
+
+ /**
+ * Handling Tags
+ */
+
+ /**
+ * Add tags to the item identified by the url. Also updates the used tags
+ * list
+ * @param {string} itemId The item identifier by item id
+ * @param {Array} tags Tags adding to the item
+ * @param {Object | undefined} options Can provide an actionInfo object with
+ * further data to send to the API. Can
+ * have success and error callbacks
+ * @return {Boolean} Returns Boolean whether the api call started sucessfully
+ */
+ function addTagsToItem(itemId, tags, options) {
+ return addTags({item_id: itemId}, tags, options);
+ }
+
+ /**
+ * Add tags to the item identified by the url. Also updates the used tags
+ * list
+ * @param {string} url The item identifier by url
+ * @param {Array} tags Tags adding to the item
+ * @param {Object} options Can provide an actionInfo object with further
+ * data to send to the API. Can have success and error
+ * callbacks
+ * @return {Boolean} Returns Boolean whether the api call started sucessfully
+ */
+ function addTagsToURL(url, tags, options) {
+ return addTags({url: url}, tags, options);
+ }
+
+ /**
+ * Helper function to execute the add tags api call. Will be used from addTagsToURL
+ * and addTagsToItem but not exposed outside
+ * @param {string} actionPart Specific action part to add to action
+ * @param {Array} tags Tags adding to the item
+ * @param {Object | undefined} options Can provide an actionInfo object with
+ * further data to send to the API. Can
+ * have success and error callbacks
+ * @return {Boolean} Returns Boolean whether the api call started sucessfully
+ */
+ function addTags(actionPart, tags, options) {
+ // Tags add action
+ var action = {
+ action: "tags_add",
+ tags: tags
+ };
+ action = extend(action, actionPart);
+
+ // Backup the success callback as we need it later
+ var finalSuccessCallback = options.success;
+
+ // Switch the success callback
+ options.success = function(data) {
+
+ // Update used tags
+ var usedTagsJSON = getSetting("usedTags");
+ var usedTags = usedTagsJSON ? JSON.parse(usedTagsJSON) : {};
+
+ // Check for each tag if it's already in the used tags
+ for (var i = 0; i < tags.length; i++) {
+ var tagToSave = tags[i].trim();
+ var newUsedTagObject = {
+ "tag": tagToSave,
+ "timestamp": new Date().getTime()
+ };
+ usedTags[tagToSave] = newUsedTagObject;
+ }
+ setSetting("usedTags", JSON.stringify(usedTags));
+
+ // Let the callback know that we are finished
+ if (finalSuccessCallback) {
+ finalSuccessCallback(data);
+ }
+ };
+
+ // Execute the action
+ return sendAction(action, options);
+ }
+
+ /**
+ * Get all cached tags and used tags within the callback
+ * @param {function(Array, Array, Boolean)} callback
+ * Function with tags and used tags as parameter.
+ */
+ function getTags(callback) {
+
+ var tagsFromSettings = function() {
+ var tagsJSON = getSetting("tags");
+ if (typeof tagsJSON !== "undefined") {
+ return JSON.parse(tagsJSON)
+ }
+ return [];
+ }
+
+ var sortedUsedTagsFromSettings = function() {
+ // Get and Sort used tags
+ var usedTags = [];
+
+ var usedTagsJSON = getSetting("usedTags");
+ if (typeof usedTagsJSON !== "undefined") {
+ var usedTagsObject = JSON.parse(usedTagsJSON);
+ var usedTagsObjectArray = [];
+ for (var tagKey in usedTagsObject) {
+ usedTagsObjectArray.push(usedTagsObject[tagKey]);
+ }
+
+ // Sort usedTagsObjectArray based on timestamp
+ usedTagsObjectArray.sort(function(usedTagA, usedTagB) {
+ var a = usedTagA.timestamp;
+ var b = usedTagB.timestamp;
+ return a - b;
+ });
+
+ // Get all keys tags
+ for (var j = 0; j < usedTagsObjectArray.length; j++) {
+ usedTags.push(usedTagsObjectArray[j].tag);
+ }
+
+ // Reverse to set the last recent used tags to the front
+ usedTags.reverse();
+ }
+
+ return usedTags;
+ }
+
+ if (callback) {
+ var tags = tagsFromSettings();
+ var usedTags = sortedUsedTagsFromSettings();
+ callback(tags, usedTags);
+ }
+ }
+
+ /**
+ * Fetch suggested tags for a given item id
+ * @param {string} itemId Item id of
+ * @param {Object | undefined} options Can provide an actionInfo object
+ * with further data to send to the API.
+ * Can have success and error callbacks
+ * @return {Boolean} Returns Boolean whether the api call started sucessfully
+ */
+ function getSuggestedTagsForItem(itemId, options) {
+ return getSuggestedTags({item_id: itemId}, options);
+ }
+
+ /**
+ * Fetch suggested tags for a given URL
+ * @param {string} url (required) The item identifier by url
+ * @param {Object} options Can provide an actionInfo object with further
+ * data to send to the API. Can have success and error
+ * callbacks
+ * @return {Boolean} Returns Boolean whether the api call started sucessfully
+ */
+ function getSuggestedTagsForURL(url, options) {
+ return getSuggestedTags({url: url}, options);
+ }
+
+ /**
+ * Helper function to get suggested tags
+ * @return {Boolean} Returns Boolean whether the api call started sucessfully
+ */
+ function getSuggestedTags(data, options) {
+
+ data = data || {};
+ options = options || {};
+
+ data.access_token = getAccessToken();
+
+ return apiRequest({
+ path: "/getSuggestedTags",
+ data: data,
+ success: options.success,
+ error: options.error
+ });
+ }
+
+ /**
+ * Helper function to get current signup AB group the user is in
+ */
+ function getSignupPanelTabTestVariant() {
+ return getMultipleTestOption('panelSignUp', {control: 1, v1: 8, v2: 1 })
+ }
+
+ function getMultipleTestOption(testName, testOptions) {
+ // Get the test from preferences if we've already assigned the user to a test
+ var settingName = 'test.' + testName;
+ var assignedValue = getSetting(settingName);
+ var valArray = [];
+
+ // If not assigned yet, pick and store a value
+ if (!assignedValue)
+ {
+ // Get a weighted array of test variants from the testOptions object
+ Object.keys(testOptions).forEach(function(key) {
+ for (var i = 0; i < testOptions[key]; i++) {
+ valArray.push(key);
+ }
+ });
+
+ // Get a random test variant and set the user to it
+ assignedValue = valArray[Math.floor(Math.random() * valArray.length)];
+ setSetting(settingName, assignedValue);
+ }
+
+ return assignedValue;
+
+ }
+
+ /**
+ * Public functions
+ */
+ return {
+ isUserLoggedIn : isUserLoggedIn,
+ clearUserData: clearUserData,
+ addLink: addLink,
+ deleteItem: deleteItem,
+ addTagsToItem: addTagsToItem,
+ addTagsToURL: addTagsToURL,
+ getTags: getTags,
+ isPremiumUser: isPremiumUser,
+ getSuggestedTagsForItem: getSuggestedTagsForItem,
+ getSuggestedTagsForURL: getSuggestedTagsForURL,
+ getSignupPanelTabTestVariant: getSignupPanelTabTestVariant,
+ };
+}());
diff --git a/browser/extensions/pocket/content/pocket-content-process.js b/browser/extensions/pocket/content/pocket-content-process.js
new file mode 100644
index 000000000..9b158a0ed
--- /dev/null
+++ b/browser/extensions/pocket/content/pocket-content-process.js
@@ -0,0 +1,54 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+"use strict";
+
+// This file is loaded as a process script, it will be loaded in the parent
+// process as well as all content processes.
+
+const { utils: Cu } = Components;
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("chrome://pocket/content/AboutPocket.jsm");
+
+function AboutPocketChildListener() {
+}
+AboutPocketChildListener.prototype = {
+ onStartup: function onStartup() {
+
+ // Only do this in content processes since, as the broadcaster of this
+ // message, the parent process doesn't also receive it. We handlers
+ // the shutting down separately.
+ if (Services.appinfo.processType ==
+ Services.appinfo.PROCESS_TYPE_CONTENT) {
+
+ Services.cpmm.addMessageListener("PocketShuttingDown", this, true);
+ }
+
+ AboutPocket.aboutSaved.register();
+ AboutPocket.aboutSignup.register();
+ },
+
+ onShutdown: function onShutdown() {
+ AboutPocket.aboutSignup.unregister();
+ AboutPocket.aboutSaved.unregister();
+
+ Services.cpmm.removeMessageListener("PocketShuttingDown", this);
+ Cu.unload("chrome://pocket/content/AboutPocket.jsm");
+ },
+
+ receiveMessage: function receiveMessage(message) {
+ switch (message.name) {
+ case "PocketShuttingDown":
+ this.onShutdown();
+ break;
+ default:
+ break;
+ }
+
+ return;
+ }
+};
+
+const listener = new AboutPocketChildListener();
+listener.onStartup();
diff --git a/browser/extensions/pocket/install.rdf.in b/browser/extensions/pocket/install.rdf.in
new file mode 100644
index 000000000..babccfa5a
--- /dev/null
+++ b/browser/extensions/pocket/install.rdf.in
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+#filter substitution
+
+<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:em="http://www.mozilla.org/2004/em-rdf#">
+
+ <Description about="urn:mozilla:install-manifest">
+ <em:id>firefox@getpocket.com</em:id>
+ <em:version>1.0.5</em:version>
+ <em:type>2</em:type>
+ <em:bootstrap>true</em:bootstrap>
+ <em:multiprocessCompatible>true</em:multiprocessCompatible>
+
+ <!-- Target Application this theme can install into,
+ with minimum and maximum supported versions. -->
+ <em:targetApplication>
+ <Description>
+ <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
+ <em:minVersion>@MOZ_APP_VERSION@</em:minVersion>
+ <em:maxVersion>@MOZ_APP_MAXVERSION@</em:maxVersion>
+ </Description>
+ </em:targetApplication>
+
+ <!-- Front End MetaData -->
+ <em:name>Pocket</em:name>
+ <em:description>When you find something you want to view later, put it in Pocket.</em:description>
+ </Description>
+</RDF>
diff --git a/browser/extensions/pocket/jar.mn b/browser/extensions/pocket/jar.mn
new file mode 100644
index 000000000..5fab627fe
--- /dev/null
+++ b/browser/extensions/pocket/jar.mn
@@ -0,0 +1,32 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+[features/firefox@getpocket.com] chrome.jar:
+% content pocket %content/ contentaccessible=yes
+% skin pocket classic/1.0 %skin/linux/
+% skin pocket classic/1.0 %skin/osx/ os=Darwin
+% skin pocket classic/1.0 %skin/windows/ os=WINNT
+% skin pocket-shared classic/1.0 %skin/shared/
+ content/ (content/*)
+ skin/ (skin/*)
+# windows overrides
+% override chrome://pocket/skin/menuPanel.png chrome://pocket/skin/menuPanel-aero.png os=WINNT osversion=6
+% override chrome://pocket/skin/menuPanel.png chrome://pocket/skin/menuPanel-aero.png os=WINNT osversion=6.1
+% override chrome://pocket/skin/menuPanel@2x.png chrome://pocket/skin/menuPanel-aero@2x.png os=WINNT osversion=6
+% override chrome://pocket/skin/menuPanel@2x.png chrome://pocket/skin/menuPanel-aero@2x.png os=WINNT osversion=6.1
+% override chrome://pocket/skin/Toolbar@2x.png chrome://pocket/skin/Toolbar-aero@2x.png os=WINNT osversion=6
+% override chrome://pocket/skin/Toolbar@2x.png chrome://pocket/skin/Toolbar-aero@2x.png os=WINNT osversion=6.1
+% override chrome://pocket/skin/Toolbar@2x.png chrome://pocket/skin/Toolbar-win8@2x.png os=WINNT osversion=6.2
+% override chrome://pocket/skin/Toolbar@2x.png chrome://pocket/skin/Toolbar-win8@2x.png os=WINNT osversion=6.3
+% override chrome://pocket/skin/Toolbar.png chrome://pocket/skin/Toolbar-XP.png os=WINNT osversion<6
+% override chrome://pocket/skin/Toolbar.png chrome://pocket/skin/Toolbar-aero.png os=WINNT osversion=6
+% override chrome://pocket/skin/Toolbar.png chrome://pocket/skin/Toolbar-aero.png os=WINNT osversion=6.1
+% override chrome://pocket/skin/Toolbar.png chrome://pocket/skin/Toolbar-win8.png os=WINNT osversion=6.2
+% override chrome://pocket/skin/Toolbar.png chrome://pocket/skin/Toolbar-win8.png os=WINNT osversion=6.3
+# osx overrides
+% override chrome://pocket/skin/Toolbar.png chrome://pocket/skin/Toolbar-yosemite.png os=Darwin osversion>=10.10
+% override chrome://pocket/skin/Toolbar@2x.png chrome://pocket/skin/Toolbar-yosemite@2x.png os=Darwin osversion>=10.10
+% override chrome://pocket/skin/menuPanel.png chrome://pocket/skin/menuPanel-yosemite.png os=Darwin osversion>=10.10
+% override chrome://pocket/skin/menuPanel@2x.png chrome://pocket/skin/menuPanel-yosemite@2x.png os=Darwin osversion>=10.10
+
diff --git a/browser/extensions/pocket/locale/ast/pocket.properties b/browser/extensions/pocket/locale/ast/pocket.properties
new file mode 100644
index 000000000..c32e53b54
--- /dev/null
+++ b/browser/extensions/pocket/locale/ast/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Amestar etiquetes
+alreadyhaveacct = ¿Yá yes un usuariu de Pocket?
+continueff = Siguir con Firefox
+errorgeneric = Hebo un fallu tentando de guardar en Pocket.
+learnmore = Depriendi más
+loginnow = Aniciar sesión
+maxtaglength = Les etiquetes lléndense a 25 caráuteres
+mustbeconnected = Has tar coneutáu a internet pa guardar en Pocket. Comprueba la to conexón y volvi tentalo, por favor.
+onlylinkssaved = Namái puen guardase enllaces
+pagenotsaved = Páxina non guardada
+pageremoved = Páxina desaniciada
+pagesaved = Guardóse en Pocket
+processingremove = Desaniciando páxina…
+processingtags = Amestando etiquetes…
+removepage = Desanicia páxina
+save = Guardar
+saving = Guardando…
+signupemail = Rexistrase con corréu
+signuptosave = Rexístrate en Pocket. Ye de baldre.
+suggestedtags = Etiquetes suxeríes
+tagline = Guardar artículos y vídeos dende Firefox pa ver en Pocket o en cualquier preséu, en cualquier momentu.
+taglinestory_one = Fai clic nel botón de Pocket pa guardar cualquier artículu, videu o páxina dende Firefox.
+taglinestory_two = Ver en Pocker o en cualquier preséu, en cualquier momentu.
+tagssaved = Etiquetes amestaes
+tos = Sigiuiendo, tas acordies colos <a href="%1$S" target="_blank">Términos de Serviciu</a> y la <a href="%2$S" target="_blank">Política de privacidá</a> de Pocket
+tryitnow = Pruébalu agora
+signinfirefox = Anicia sesión con Firefox
+signupfirefox = Rexístrate con Firefox
+viewlist = Ver llista
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Guardar en Pocket
+saveToPocketCmd.label = Guardar páxina en Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Guardar enllaz en Pocket
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Ver la llista de Pocket
diff --git a/browser/extensions/pocket/locale/az/pocket.properties b/browser/extensions/pocket/locale/az/pocket.properties
new file mode 100644
index 000000000..a228ca026
--- /dev/null
+++ b/browser/extensions/pocket/locale/az/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Etiket əlavə et
+alreadyhaveacct = Artıq Pocket istifadəçisisiniz?
+continueff = Firefox ilə davam et
+errorgeneric = Pocket-ə saxlarkən xəta baş verdi.
+learnmore = Ətraflı Öyrən
+loginnow = Daxil ol
+maxtaglength = Etiketlər 25 simvol ilə limitlidir
+mustbeconnected = Pocket-ə saxlamaq üçün internetə qoşulu olmalısınız. Lütfən internetə qoşulu olduğunuza əmin olub təkrar yoxlayın.
+onlylinkssaved = Ancaq keçidlər saxlana bilər
+pagenotsaved = Səhifə saxlanmadı
+pageremoved = Səhifə silindi
+pagesaved = Pocket-ə saxlandı
+processingremove = Səhifə silinir…
+processingtags = Etiketlər əlavə edilir…
+removepage = Səhifəni sil
+save = Saxla
+saving = Saxlanır…
+signupemail = E-poçt ilə qeyd ol
+signuptosave = Pocket üçün qeyd ol. Bu pulsuzdur.
+suggestedtags = Məsləhərli etiketlər
+tagline = Firefoxdan məqalə və videoları Pocket-ə saxlayın, istədiyiniz vaxt, istədiyiniz yerdə baxın.
+taglinestory_one = Firefoxda hər hansı bir məqalə, video və ya səhifəni saxlamaq üçün Pocket Düyməsinə klikləyin.
+taglinestory_two = İstənilən cihazda, istənilən vaxt Pocket-də görün.
+tagssaved = Etiketlər əlavə edildi
+tos = Davam etməklə, Pocket-in <a href="%1$S" target="_blank">İstifadə Şərtləri</a> və <a href="%2$S" target="_blank">Məxfilik Siyasəti</a> ilə razılaşmış olursunuz
+tryitnow = İndi Yoxlayın
+signinfirefox = Firefox ilə daxil ol
+signupfirefox = Firefox ilə qeyd ol
+viewlist = Siyahını gör
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Pocket-ə Saxla
+saveToPocketCmd.label = Səhifəni Pocket-ə Saxla
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Keçidi Pocket-ə Saxla
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Pocket Siyahısını Gör
diff --git a/browser/extensions/pocket/locale/bg/pocket.properties b/browser/extensions/pocket/locale/bg/pocket.properties
new file mode 100644
index 000000000..ba86dd7f6
--- /dev/null
+++ b/browser/extensions/pocket/locale/bg/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Добавяне на етикети
+alreadyhaveacct = Вече сте потребител на Pocket?
+continueff = Продължаване с Firefox
+errorgeneric = Получи се грешка при опит за запис в Pocket.
+learnmore = Научете повече
+loginnow = Вписване
+maxtaglength = Етикетите могат да са до 25 знака
+mustbeconnected = Трябва да сте свързан към Интернет, за да запазвате в Pocket. Моля, проверете свързаността си с Интернет и пробвайте отново.
+onlylinkssaved = Могат да бъдат запазвани само връзки
+pagenotsaved = Страницата не е запазена
+pageremoved = Страницата е премахната
+pagesaved = Запазена в Pocket
+processingremove = Премахване на страница…
+processingtags = Добавяне на етикети…
+removepage = Премахване на страница
+save = Запазване
+saving = Запазване…
+signupemail = Регистриране с мейл
+signuptosave = Регистрирайте се в Pocket. Безплатно е.
+suggestedtags = Предложени етикети
+tagline = Запазвайте статии и видеота от Firefox и можете да ги преглеждате в Pocket на всяко устройство по всяко време.
+taglinestory_one = Щракнете на бутона на Pocket за запазване на статия, видео или страница от Firefox.
+taglinestory_two = Преглеждайте в Pocket на всяко устройство и по всяко време.
+tagssaved = Етикетите са добавени
+tos = Продължавайки, вие се съгласявате с <a href="%1$S" target="_blank">Условията за ползване</a> и <a href="%2$S" target="_blank">Политиката за поверителност</a> на Pocket
+tryitnow = Опитайте сега
+signinfirefox = Вписване с Firefox
+signupfirefox = Регистриране с Firefox
+viewlist = Преглед на списъка
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Запазване в Pocket
+saveToPocketCmd.label = Запазване на страницата в Pocket
+saveToPocketCmd.accesskey = с
+saveLinkToPocketCmd.label = Запазване на връзката в Pocket
+saveLinkToPocketCmd.accesskey = в
+pocketMenuitem.label = Преглед списъка на Pocket
diff --git a/browser/extensions/pocket/locale/bn-BD/pocket.properties b/browser/extensions/pocket/locale/bn-BD/pocket.properties
new file mode 100644
index 000000000..7a43edad1
--- /dev/null
+++ b/browser/extensions/pocket/locale/bn-BD/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = ট্যাগ যোগ করুন
+alreadyhaveacct = আপনি Pocket ব্যবহার করছেন?
+continueff = Firefox ব্যবহার চালিয়ে যান
+errorgeneric = Pocket এ সংরক্ষণ করতে ত্রুটি ঘটেছে।
+learnmore = আরও জানুন
+loginnow = লগ ইন
+maxtaglength = ট্যাগ ২৫ অক্ষরের মধ্যে সীমাবদ্ধ
+mustbeconnected = Pocket এ কোন কিছু সংরক্ষণ করে রাখতে চাইলে, ইন্টারনেটে সংযুক্ত থাকতে হবে। ইন্টারনেট সংযোগ পরীক্ষা করুন এবং আবার চেষ্টা করুন।
+onlylinkssaved = শুধু লিঙ্ক সংরক্ষণ করা যাবে
+pagenotsaved = পাতা সংরক্ষণ করা হয়নি
+pageremoved = পাতা অপসারণ করা হয়েছে
+pagesaved = Pocket এ সংরক্ষিত হয়েছে
+processingremove = পাতা অপসারিত হচ্ছে…
+processingtags = ট্যাগ যুক্ত করা হচ্ছে…
+removepage = পেজ মুছে ফেলুন
+save = সংরক্ষণ
+saving = সংরক্ষণ করা হচ্ছে...
+signupemail = ইমেইল দিয়ে সাইন আপ করুন
+signuptosave = Pocket সাইন আপ করুন। এটি মুফত।
+suggestedtags = প্রস্তাবিত ট্যাগ
+tagline = Pocket এর মাধ্যমে যেকোন সময়, যেকোন ডিভাইসে নিবন্ধ এবং ভিডিও দেখতে Firefox থেকে সেগুলো সংরক্ষণ করুন।
+taglinestory_one = Firefox থেকে আর্টিকেল, ভিডিও বা পৃষ্ঠা সংরক্ষণ করার জন্য Pocket বাটন ক্লিক করুন।
+taglinestory_two = যেকোন সময়ে, যেকোন স্থানে Pocket এ দেখুন।
+tagssaved = ট্যাগ যোগ করা হয়েছে
+tos = এটি অব্যহত রেখে, আপনি Pocket এর <a href="%1$S" target="_blank">সেবার শর্তাবলী</a> এবং <a href="%2$S" target="_blank">গোপনীয়তা নীতিমালায়</a> সম্মত হবেন।
+tryitnow = এখনই ব্যবহার করুন
+signinfirefox = ফায়ারফক্স দিয়ে সাইন ইন করুন
+signupfirefox = ফায়ারফক্স দিয়ে সাইন আপ করুন
+viewlist = তালিকা দেখুন
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Pocket এ সংরক্ষণ করুন
+saveToPocketCmd.label = Pocket এ পাতাটি সংরক্ষণ করুন k
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Pocket এ লিঙ্কটি সংরক্ষণ করুন o
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Pocket তালিকা দেখুন
diff --git a/browser/extensions/pocket/locale/cs/pocket.properties b/browser/extensions/pocket/locale/cs/pocket.properties
new file mode 100644
index 000000000..619b0a01a
--- /dev/null
+++ b/browser/extensions/pocket/locale/cs/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Přidat štítky
+alreadyhaveacct = Jste již uživatel služby Pocket?
+continueff = Pokračovat pomocí Firefoxu
+errorgeneric = Při pokusu o uložení do služby Pocket došlo k chybě.
+learnmore = Zjistit více
+loginnow = Přihlásit se
+maxtaglength = Štítky jsou omezeny na 25 znaků
+mustbeconnected = Abyste mohli ukládat do služby Pocket, musíte být připojeni k internetu. Zkontrolujte prosím své připojení a zkuste to znovu.
+onlylinkssaved = Pouze odkazy mohou být uloženy
+pagenotsaved = Stránka nebyla uložena
+pageremoved = Stránka byla odstraněna
+pagesaved = Uloženo do služby Pocket
+processingremove = Odstraňování stránky…
+processingtags = Přidávání štítků…
+removepage = Odstranit stránku
+save = Uložit
+saving = Ukládání…
+signupemail = Registrace e-mailem
+signuptosave = Registrujte se do služby Pocket. Je to zdarma.
+suggestedtags = Doporučené štítky
+tagline = Ukládejte si články a videa z Firefoxu pro zobrazení ve službě Pocket kdykoliv a na jakémkoli zařízení.
+taglinestory_one = Klepněte na tlačítko služby Pocket pro uložení jakéhokoliv článku, videa nebo stránky přímo z Firefoxu.
+taglinestory_two = Zobrazení ve službě Pocket kdykoliv a na jakémkoliv zařízení.
+tagssaved = Štítky přidány
+tos = Pokračování souhlasíte s <a href="%1$S" target="_blank">Podmínkami služby</a> Pocket a <a href="%2$S" target="_blank">Zásadami ochrany osobních údajů</a>
+tryitnow = Vyzkoušejte nyní
+signinfirefox = Přihlášení ve Firefoxu
+signupfirefox = Registrace ve Firefoxu
+viewlist = Zobrazit seznam
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Uloží do služby Pocket
+saveToPocketCmd.label = Uložit stránku do služby Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Uložit odkaz do služby Pocket
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Zobrazit seznam služby Pocket
diff --git a/browser/extensions/pocket/locale/da/pocket.properties b/browser/extensions/pocket/locale/da/pocket.properties
new file mode 100644
index 000000000..5e5438359
--- /dev/null
+++ b/browser/extensions/pocket/locale/da/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Tilføj tags
+alreadyhaveacct = Er du allerede Pocket-bruger?
+continueff = Fortsæt med Firefox
+errorgeneric = Der opstod en fejl ved forsøg på at gemme til Pocket.
+learnmore = Læs mere
+loginnow = Log ind
+maxtaglength = Tags er begrænset til 25 tegn
+mustbeconnected = Du skal have forbindelse til internettet for at kunne gemme til Pocket. Kontroller din internetforbindelse og prøv igen.
+onlylinkssaved = Kun links kan gemmes
+pagenotsaved = Siden blev ikke gemt
+pageremoved = Siden er fjernet
+pagesaved = Gemt til Pocket
+processingremove = Fjerner side…
+processingtags = Tilføjer tags…
+removepage = Fjern side
+save = Gem
+saving = Gemmer…
+signupemail = Log ind med mailadresse
+signuptosave = Meld dig til Pocket. Det er gratis.
+suggestedtags = Foreslåede tags
+tagline = Gemmer artikler og videoer fra Firefox i Pocket, så du senere kan se dem hvor og hvornår, du har lyst.
+taglinestory_one = Klik på knappen Pocket for at gemme en artikel, video eller webside fra Firefox.
+taglinestory_two = Se i Pocket hvor og hvornår, du har lyst.
+tagssaved = Tags tilføjet
+tos = Fortsætter du, accepterer du Pockets <a href="%1$S" target="_blank">tjenestevilkår</a> og <a href="%2$S" target="_blank">privatlivspolitik</a>
+tryitnow = Prøv det nu
+signinfirefox = Log ind med Firefox
+signupfirefox = Meld dig til med Firefox
+viewlist = Vis liste
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Gem til Pocket
+saveToPocketCmd.label = Gem siden til Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Gem link til Pocket
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Vis Pocket-liste
diff --git a/browser/extensions/pocket/locale/de/pocket.properties b/browser/extensions/pocket/locale/de/pocket.properties
new file mode 100644
index 000000000..f02f5da05
--- /dev/null
+++ b/browser/extensions/pocket/locale/de/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Tags hinzufügen
+alreadyhaveacct = Sind Sie bereits Pocket-Nutzer?
+continueff = Mit Firefox fortfahren
+errorgeneric = Beim Speichern des Links bei Pocket ist ein Fehler aufgetreten.
+learnmore = Mehr erfahren
+loginnow = Anmelden
+maxtaglength = Tags dürfen höchsten 25 Zeichen lang sein.
+mustbeconnected = Bitte überprüfen Sie, ob Sie mit dem Internet verbunden sind.
+onlylinkssaved = Es können nur Links gespeichert werden
+pagenotsaved = Seite nicht gespeichert
+pageremoved = Seite entfernt
+pagesaved = Bei Pocket gespeichert
+processingremove = Seite wird entfernt…
+processingtags = Tags werden hinzugefügt…
+removepage = Seite entfernen
+save = Speichern
+saving = Speichern…
+signupemail = Mit E-Mail registrieren
+signuptosave = Registrieren Sie sich bei Pocket. Das ist kostenlos.
+suggestedtags = Vorgeschlagene Tags
+tagline = Speichern Sie Artikel und Videos aus Firefox bei Pocket, um sie jederzeit und auf jedem Gerät ansehen zu können.
+taglinestory_one = Klicken Sie auf die Pocket-Schaltfläche, um beliebige Artikel, Videos und Seiten aus Firefox zu speichern.
+taglinestory_two = Lesen Sie diese mit Pocket, jederzeit und auf jedem Gerät.
+tagssaved = Tags hinzugefügt
+tos = Indem Sie fortfahren, akzeptieren Sie die <a href="%1$S" target="_blank">Nutzungsbedingungen</a> und die <a href="%2$S" target="_blank">Datenschutzerklärung</a> von Pocket.
+tryitnow = Jetzt ausprobieren
+signinfirefox = Mit Firefox anmelden
+signupfirefox = Mit Firefox registrieren
+viewlist = Liste anzeigen
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Bei Pocket speichern
+saveToPocketCmd.label = Seite bei Pocket speichern
+saveToPocketCmd.accesskey = b
+saveLinkToPocketCmd.label = Link bei Pocket speichern
+saveLinkToPocketCmd.accesskey = c
+pocketMenuitem.label = Pocket-Liste anzeigen
diff --git a/browser/extensions/pocket/locale/dsb/pocket.properties b/browser/extensions/pocket/locale/dsb/pocket.properties
new file mode 100644
index 000000000..a878de329
--- /dev/null
+++ b/browser/extensions/pocket/locale/dsb/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Wobznamjenja pśidaś
+alreadyhaveacct = Sćo južo wužywaŕ Pocket?
+continueff = Z Firefox pókšacowaś
+errorgeneric = Pśi składowanju do Pocket jo zmólka nastała.
+learnmore = Dalšne informacije
+loginnow = Pśizjawiś
+maxtaglength = Wobznamjenja su na 25 znamuškow wobgranicowane
+mustbeconnected = Musyśo z internetom zwězany byś, aby do Pocket składował. Pšosym pśeglědajśo swój zwisk a wopytajśo hyšći raz.
+onlylinkssaved = Jano wótkaze daju se składowaś
+pagenotsaved = Bok njejo se składł
+pageremoved = Bok jo se wótwónoźeł
+pagesaved = Do Pocket skłaźony
+processingremove = Bok se wótwónoźujo…
+processingtags = Wobznamjenja se pśidawaju…
+removepage = Bok wótwónoźeś
+save = Składowaś
+saving = Składujo se…
+signupemail = Registrěrujśo se z mejlku
+signuptosave = Registrěrujśo se za Pocket. Jo dermo.
+suggestedtags = Naraźone wobznamjenja
+tagline = Składujśo nastawki a wideo z Firefox, aby se je kuždy cas w Pocket na kuždem rěźe woglědał.
+taglinestory_one = Klikniśo na tłocašk Pocket, aby nastawk, wideo abo bok z Firefox składował.
+taglinestory_two = Se w Pocket na kuždem rěźee kuždy cas woglědaś.
+tagssaved = Wobznamjenja su se pśidali
+tos = Gaž pókšacujośo, zwólijośo do <a href="%1$S" target="_blank">wužywarskich wuměnjenjow</a> a <a href="%2$S" target="_blank">pšawidłow priwatnosći</a> Pocket
+tryitnow = Wopytajśo to něnto
+signinfirefox = Z Firefox pśizjawiś
+signupfirefox = Z Firefox registrěrowaś
+viewlist = Lisćinu pokazaś
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Do Pocket składowaś
+saveToPocketCmd.label = Bok do Pocket składowaś
+saveToPocketCmd.accesskey = b
+saveLinkToPocketCmd.label = Wótkaz do Pocket składowaś
+saveLinkToPocketCmd.accesskey = w
+pocketMenuitem.label = Lisćinu Pocket pokazaś
diff --git a/browser/extensions/pocket/locale/en-GB/pocket.properties b/browser/extensions/pocket/locale/en-GB/pocket.properties
new file mode 100644
index 000000000..bddd825c5
--- /dev/null
+++ b/browser/extensions/pocket/locale/en-GB/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Add Tags
+alreadyhaveacct = Already a Pocket user?
+continueff = Continue with Firefox
+errorgeneric = There was an error when trying to save to Pocket.
+learnmore = Learn More
+loginnow = Log in
+maxtaglength = Tags are limited to 25 characters
+mustbeconnected = You must be connected to the Internet in order to save to Pocket. Please check your connection and try again.
+onlylinkssaved = Only links can be saved
+pagenotsaved = Page Not Saved
+pageremoved = Page Removed
+pagesaved = Saved to Pocket
+processingremove = Removing Page…
+processingtags = Adding tags…
+removepage = Remove Page
+save = Save
+saving = Saving…
+signupemail = Sign up with email
+signuptosave = Sign up for Pocket. It’s free.
+suggestedtags = Suggested Tags
+tagline = Save articles and videos from Firefox to view in Pocket on any device, any time.
+taglinestory_one = Click the Pocket Button to save any article, video or page from Firefox.
+taglinestory_two = View in Pocket on any device, any time.
+tagssaved = Tags Added
+tos = By continuing, you agree to Pocket’s <a href="%1$S" target="_blank">Terms of Service</a> and <a href="%2$S" target="_blank">Privacy Policy</a>
+tryitnow = Try It Now
+signinfirefox = Sign in with Firefox
+signupfirefox = Sign up with Firefox
+viewlist = View List
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Save to Pocket
+saveToPocketCmd.label = Save Page to Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Save Link to Pocket
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = View Pocket List
diff --git a/browser/extensions/pocket/locale/en-US/pocket.properties b/browser/extensions/pocket/locale/en-US/pocket.properties
new file mode 100644
index 000000000..dee2681dc
--- /dev/null
+++ b/browser/extensions/pocket/locale/en-US/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Add Tags
+alreadyhaveacct = Already a Pocket user?
+continueff = Continue with Firefox
+errorgeneric = There was an error when trying to save to Pocket.
+learnmore = Learn More
+loginnow = Log in
+maxtaglength = Tags are limited to 25 characters
+mustbeconnected = You must be connected to the Internet in order to save to Pocket. Please check your connection and try again.
+onlylinkssaved = Only links can be saved
+pagenotsaved = Page Not Saved
+pageremoved = Page Removed
+pagesaved = Saved to Pocket
+processingremove = Removing Page…
+processingtags = Adding tags…
+removepage = Remove Page
+save = Save
+saving = Saving…
+signupemail = Sign up with email
+signuptosave = Sign up for Pocket. It’s free.
+suggestedtags = Suggested Tags
+tagline = Save articles and videos from Firefox to view in Pocket on any device, any time.
+taglinestory_one = Click the Pocket Button to save any article, video or page from Firefox.
+taglinestory_two = View in Pocket on any device, any time.
+tagssaved = Tags Added
+tos = By continuing, you agree to Pocket's <a href="%1$S" target="_blank">Terms of Service</a> and <a href="%2$S" target="_blank">Privacy Policy</a>
+tryitnow = Try It Now
+signinfirefox = Sign in with Firefox
+signupfirefox = Sign up with Firefox
+viewlist = View List
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Save to Pocket
+saveToPocketCmd.label = Save Page to Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Save Link to Pocket
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = View Pocket List
diff --git a/browser/extensions/pocket/locale/es-AR/pocket.properties b/browser/extensions/pocket/locale/es-AR/pocket.properties
new file mode 100644
index 000000000..2782d3ccf
--- /dev/null
+++ b/browser/extensions/pocket/locale/es-AR/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Agregar etiquetas
+alreadyhaveacct = ¿Ya es un usuario de Pocket?
+continueff = Continuar con Firefox
+errorgeneric = Hubo un error al tratar de guardar en Pocket.
+learnmore = Conocer más
+loginnow = Ingresar
+maxtaglength = Las etiquetas están limitadas a 25 caracteres
+mustbeconnected = Debe estar conectado a Internet para poder guardar en Pocket. Verifique la conexión e intente nuevamente.
+onlylinkssaved = Solamente pueden guardarle enlaces
+pagenotsaved = Página no guardada
+pageremoved = Página eliminada
+pagesaved = Guardado en Pocket
+processingremove = Eliminando página…
+processingtags = Agregando etiquetas…
+removepage = Eliminar página
+save = Guardar
+saving = Guardando…
+signupemail = Ingresar con correo electrónico
+signuptosave = Registrarse en Pocket. En grátis.
+suggestedtags = Etiquetas sugeridas
+tagline = Guardar artículos y videos desde Firefox para ver en Pocket en cualquier dispositivo en cualquier momento.
+taglinestory_one = Clic en el botón Pocket para guardar cualquier artículo, video o página desde Firefox.
+taglinestory_two = Ver en Pocket en cualquier dispositivo en cualquier momento.
+tagssaved = Etiquetas agregadas
+tos = Al continuar acepta los <a href="%1$S" target="_blank">términos de servicio</a> y la <a href="%2$S" target="_blank">política de privacidad</a> de Pocket
+tryitnow = Probalo ahora
+signinfirefox = Ingresar con Firefox
+signupfirefox = Registrarse con Firefox
+viewlist = Ver lista
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Guardar en Pocket
+saveToPocketCmd.label = Guardar página en Pocket
+saveToPocketCmd.accesskey = G
+saveLinkToPocketCmd.label = Guardar enlace en Pocket
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Ver lista de Pocket
diff --git a/browser/extensions/pocket/locale/es-CL/pocket.properties b/browser/extensions/pocket/locale/es-CL/pocket.properties
new file mode 100644
index 000000000..7a4e6872b
--- /dev/null
+++ b/browser/extensions/pocket/locale/es-CL/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Añadir etiquetas
+alreadyhaveacct = ¿Ya eres usuario de Pocket?
+continueff = Continuar con Firefox
+errorgeneric = Hubo un error al intentar guardarla en Pocket.
+learnmore = Aprender más
+loginnow = Conectarse
+maxtaglength = Las etiquetas están limitadas a 25 caracteres
+mustbeconnected = Debes estar conectado a Internet para guardar en Pocket. Por favor, revisa tu conexión y vuelve a intentarlo.
+onlylinkssaved = Solo se pueden guardar enlaces
+pagenotsaved = Página no guardada
+pageremoved = Página eliminada
+pagesaved = Guardada en Pocket
+processingremove = Eliminando página…
+processingtags = Añadiendo etiquetas…
+removepage = Eliminar página
+save = Guardar
+saving = Guardando…
+signupemail = Registrarse usando un email
+signuptosave = Registrarse en Pocket. Es gratis.
+suggestedtags = Etiquetas sugeridas
+tagline = Guarda artículos y videos desde Firefox para verlos en Pocket en cualquier dispositivo y momento.
+taglinestory_one = Aprieta el botón Pocket para guardar cualquier artículo, video o página de Firefox.
+taglinestory_two = Mírala en Pocket en cualquier dispositivo y momento
+tagssaved = Etiquetas añadidas
+tos = Al continuar, aceptas los <a href="%1$S" target="_blank">Términos del servicio</a> y la <a href="%2$S" target="_blank">Política de privacidad</a> de Pocket.
+tryitnow = Probarlo ahora
+signinfirefox = Conectarse con Firefox
+signupfirefox = Registrarse con Firefox
+viewlist = Ver lista
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Guardar en Pocket
+saveToPocketCmd.label = Guardar página en Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Guardar enlace en Pocket
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Ver lista de Pocket
diff --git a/browser/extensions/pocket/locale/es-ES/pocket.properties b/browser/extensions/pocket/locale/es-ES/pocket.properties
new file mode 100644
index 000000000..f10a20525
--- /dev/null
+++ b/browser/extensions/pocket/locale/es-ES/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Añadir etiquetas
+alreadyhaveacct = ¿Ya es usuario de Pocket?
+continueff = Continuar con Firefox
+errorgeneric = Ha sucedido un error al intentar guardar en Pocket.
+learnmore = Más información
+loginnow = Iniciar sesión
+maxtaglength = Las etiquetas están limitadas a 25 caracteres
+mustbeconnected = Debe estar conectado a Internet para poder guardar en Pocket. Compruebe su conexión y vuelva a intentarlo.
+onlylinkssaved = Solo se pueden guardar enlaces
+pagenotsaved = Página no guardada
+pageremoved = Página eliminada
+pagesaved = Guardado en Pocket
+processingremove = Eliminando página…
+processingtags = Añadiendo etiquetas…
+removepage = Eliminar página
+save = Guardar
+saving = Guardando…
+signupemail = Regístrese con su dirección de correo
+signuptosave = Regístrese en Pocket. Es gratis.
+suggestedtags = Etiquetas sugeridas
+tagline = Guarde artículos y vídeos desde Firefox para verlos en Pocket en cualquier dispositivo, en cualquier momento.
+taglinestory_one = Pulse el botón Pocket para guardar cualquier artículo, vídeo o página desde Firefox.
+taglinestory_two = Véalo en Pocket en cualquier dispositivo, en cualquier momento.
+tagssaved = Etiquetas añadidas
+tos = Al continuar, aceptas los <a href="%1$S" target="_blank">Términos del servicio</a> y la <a href="%2$S" target="_blank">Política de privacidad</a> de Pocket
+tryitnow = Pruébalo ahora
+signinfirefox = Iniciar sesión con Firefox
+signupfirefox = Registrarse con Firefox
+viewlist = Ver lista
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Guardar en Pocket
+saveToPocketCmd.label = Guardar página en Pocket
+saveToPocketCmd.accesskey = G
+saveLinkToPocketCmd.label = Guardar enlace en Pocket
+saveLinkToPocketCmd.accesskey = P
+pocketMenuitem.label = Ver la lista de Pocket
diff --git a/browser/extensions/pocket/locale/es-MX/pocket.properties b/browser/extensions/pocket/locale/es-MX/pocket.properties
new file mode 100644
index 000000000..4d2bb9c4f
--- /dev/null
+++ b/browser/extensions/pocket/locale/es-MX/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Agregar Etiquetas
+alreadyhaveacct = ¿Ya eres usuario de Pocket?
+continueff = Continúa con Firefox
+errorgeneric = Hubo un error cuando se intentaba guardar en Pocket.
+learnmore = Aprende más
+loginnow = Ingresar
+maxtaglength = Las etiquetas están limitadas a 25 caracteres
+mustbeconnected = Debes estar conectado a Internet para guardar en Pocket. Por favor, revisa tu conexión e intenta de nuevo.
+onlylinkssaved = Sólo los enlaces pueden guardarse
+pagenotsaved = Página no guardada
+pageremoved = Página eliminada
+pagesaved = Guardado en Pocket
+processingremove = Eliminando página…
+processingtags = Agregando etiquetas…
+removepage = Eliminar página
+save = Guardar
+saving = Guardando…
+signupemail = Regístrate con un correo electrónico
+signuptosave = Regístrate en Pocket. Es gratis.
+suggestedtags = Etiquetas sugeridas
+tagline = Guardar artículos y videos desde Firefox para ver en Pocket o en cualquier dispositivo, en cualquier momento.
+taglinestory_one = Haz clic en el botón de Pocket para guardar cualquier artículo, video o página desde Firefox.
+taglinestory_two = Ver en Pocker o en cualquier dispositivo, en cualquier momento.
+tagssaved = Etiquetas agregadas
+tos = Al continuar, aceptas los <a href="%1$S" target="_blank">Términos del servicio</a> y la <a href="%2$S" target="_blank">Política de privacidad</a> de Pocket
+tryitnow = Pruébalo ahora
+signinfirefox = Ingresa con Firefox
+signupfirefox = Regístrate con Firefox
+viewlist = Ver lista
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Guardar en Pocket
+saveToPocketCmd.label = Guardar página en Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Guardar enlace en Pocket
+saveLinkToPocketCmd.accesskey = n
+pocketMenuitem.label = Ver la lista de Pocket
diff --git a/browser/extensions/pocket/locale/et/pocket.properties b/browser/extensions/pocket/locale/et/pocket.properties
new file mode 100644
index 000000000..5f2d68f9c
--- /dev/null
+++ b/browser/extensions/pocket/locale/et/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Lisa silte
+alreadyhaveacct = Kas oled juba Pocketi kasutaja?
+continueff = Jätka Firefoxiga
+errorgeneric = Pocketisse salvestamisel esines viga.
+learnmore = Rohkem teavet
+loginnow = Logi sisse
+maxtaglength = Siltide pikkus võib olla kuni 25 tähemärki
+mustbeconnected = Pocketisse salvestamiseks on vajalik töötav internetiühendus. Palun kontrolli oma ühendust ja proovi uuesti.
+onlylinkssaved = Salvestada saab ainult linke
+pagenotsaved = Lehte ei salvestatud
+pageremoved = Leht eemaldati
+pagesaved = Pocketisse salvestatud
+processingremove = Lehe eemaldamine…
+processingtags = Siltide lisamine…
+removepage = Eemalda leht
+save = Salvesta
+saving = Salvestamine…
+signupemail = Registreeru e-posti teel
+signuptosave = Liitu Pocketiga. See on tasuta.
+suggestedtags = Soovitatud sildid
+tagline = Salvesta Firefoxist artikleid ja videoid, et vaadata neid Pocketist kõigil seadmeil just siis, kui ise soovid.
+taglinestory_one = Artikli, video või lehe salvestamiseks klõpsa Pocketi nupul.
+taglinestory_two = Vaata Pocketist kõigil seadmeil just siis, kui ise soovid.
+tagssaved = Sildid on lisatud
+tos = Jätkates nõustud Pocket'i <a href="%1$S" target="_blank">kasutustingimuste</a> ja <a href="%2$S" target="_blank">privaatsuspoliitikaga</a>.
+tryitnow = Proovi kohe
+signinfirefox = Logi sisse Firefoxiga
+signupfirefox = Registreeru Firefoxiga
+viewlist = Vaata nimekirja
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Salvesta Pocketisse
+saveToPocketCmd.label = Salvesta leht Pocketisse
+saveToPocketCmd.accesskey = l
+saveLinkToPocketCmd.label = Salvesta link Pocketisse
+saveLinkToPocketCmd.accesskey = i
+pocketMenuitem.label = Vaata Pocketi nimekirja
diff --git a/browser/extensions/pocket/locale/fi/pocket.properties b/browser/extensions/pocket/locale/fi/pocket.properties
new file mode 100644
index 000000000..3cd47e891
--- /dev/null
+++ b/browser/extensions/pocket/locale/fi/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Lisää tunnisteita
+alreadyhaveacct = Oletko jo Pocket-palvelun käyttäjä?
+continueff = Jatka Firefoxin parissa
+errorgeneric = Tapahtui virhe tallennettaessa Pocket-palveluun.
+learnmore = Lue lisää
+loginnow = Kirjaudu sisään
+maxtaglength = Tunnisteet voivat olla enintään 25 merkkiä pitkiä
+mustbeconnected = Tarvitset aktiivisen Internet-yhteyden talllentaaksesi sivuja Pocket-palveluun. Tarkista Internet-yhteytesi ja yritä uudestaan.
+onlylinkssaved = Vain linkkejä voidaan tallentaa
+pagenotsaved = Sivua ei ole tallennettu
+pageremoved = Sivu poistettiin
+pagesaved = Tallennettiin Pocket-palveluun
+processingremove = Poistetaan sivu…
+processingtags = Lisätään tunnisteet…
+removepage = Poista sivu
+save = Tallenna
+saving = Tallennetaan…
+signupemail = Rekisteröidy sähköpostiosoitteella
+signuptosave = Rekisteröidy Pocket-palveluun. Se on ilmaista.
+suggestedtags = Ehdotetut tunnisteet
+tagline = Tallenna artikkelit ja videot Firefoxista Pocket-palveluun katseltaviksi millä tahansa laitteella, koska tahansa.
+taglinestory_one = Napsauta Pocket-painiketta tallentaaksesi artikkelin, videon tai sivun Firefoxissa.
+taglinestory_two = Katsele Pocket-palvelussa millä tahansa laitteella, koska tahansa.
+tagssaved = Tunnisteet lisättiin
+tos = Jatkamalla hyväksyt Pocketin <a href="%1$S" target="_blank">käyttöehdot</a> ja <a href="%2$S" target="_blank">tietosuojakäytännön</a>
+tryitnow = Kokeile nyt
+signinfirefox = Kirjaudu sisään Firefox-tilillä
+signupfirefox = Rekisteröidy Firefox-tilillä
+viewlist = Näytä lista
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Tallenna Pocket-palveluun
+saveToPocketCmd.label = Tallenna sivu Pocket-palveluun
+saveToPocketCmd.accesskey = c
+saveLinkToPocketCmd.label = Tallenna linkki Pocket-palveluun
+saveLinkToPocketCmd.accesskey = k
+pocketMenuitem.label = Näytä Pocket-palvelun lista
diff --git a/browser/extensions/pocket/locale/fr/pocket.properties b/browser/extensions/pocket/locale/fr/pocket.properties
new file mode 100644
index 000000000..cb9b0ca8f
--- /dev/null
+++ b/browser/extensions/pocket/locale/fr/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Ajouter des étiquettes
+alreadyhaveacct = Vous utilisez déjà Pocket ?
+continueff = Continuer avec Firefox
+errorgeneric = Une erreur s’est produite lors de l’enregistrement dans Pocket.
+learnmore = En savoir plus
+loginnow = Connectez-vous
+maxtaglength = Les étiquettes sont limitées à 25 caractères
+mustbeconnected = Vous devez être connecté à Internet pour enregistrer des liens dans Pocket. Veuillez vérifier votre connexion puis réessayer.
+onlylinkssaved = Seuls les liens peuvent être enregistrés
+pagenotsaved = Page non enregistrée
+pageremoved = Page supprimée
+pagesaved = Page enregistrée dans Pocket
+processingremove = Suppression de la page…
+processingtags = Ajout des étiquettes…
+removepage = Supprimer la page
+save = Enregistrer
+saving = Enregistrement…
+signupemail = S’inscrire avec une adresse électronique
+signuptosave = Inscrivez-vous à Pocket, c’est gratuit.
+suggestedtags = Étiquettes suggérées
+tagline = Enregistrez des articles et des vidéos depuis Firefox pour les visualiser dans Pocket sur n’importe quel appareil, à tout moment.
+taglinestory_one = Cliquez sur le bouton Pocket pour enregistrer depuis Firefox n’importe quel article, vidéo ou page.
+taglinestory_two = Affichez vos pages dans Pocket sur n’importe quel appareil, à tout moment.
+tagssaved = Étiquettes ajoutées
+tos = En continuant, vous acceptez les <a href="%1$S" target="_blank">conditions d’utilisation</a> et la <a href="%2$S" target="_blank">politique de confidentialité</a> de Pocket
+tryitnow = Essayer
+signinfirefox = Connexion via Firefox
+signupfirefox = S’inscrire avec Firefox
+viewlist = Afficher la liste
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Enregistrer dans Pocket
+saveToPocketCmd.label = Enregistrer la page dans Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Enregistrer le lien dans Pocket
+saveLinkToPocketCmd.accesskey = k
+pocketMenuitem.label = Afficher la liste Pocket
diff --git a/browser/extensions/pocket/locale/fy-NL/pocket.properties b/browser/extensions/pocket/locale/fy-NL/pocket.properties
new file mode 100644
index 000000000..5b41c652f
--- /dev/null
+++ b/browser/extensions/pocket/locale/fy-NL/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Labels tafoegje
+alreadyhaveacct = Al in Pocket-brûker?
+continueff = Trochgean mei Firefox
+errorgeneric = Der is in flater bard by it bewarjen nei Pocket.
+learnmore = Mear ynfo
+loginnow = Meld jo oan
+maxtaglength = Labels binne beheint ta 25 tekens
+mustbeconnected = Jo moatte mei it ynternet ferbûn wêze om nei Pocket bewarje te kinnen. Kontrolearje jo ferbining en probearje it opnij.
+onlylinkssaved = Allinnich keppelingen kinne bewarre wurde
+pagenotsaved = Side net bewarre
+pageremoved = Side fuortsmiten
+pagesaved = Bewarre nei Pocket
+processingremove = Side fuortsmite…
+processingtags = Labels tafoegje…
+removepage = Side fuortsmite
+save = Bewarje
+saving = Bewarje…
+signupemail = Registrearje mei e-mailadres
+signuptosave = Registrearje foar Pocket. It is fergees.
+suggestedtags = Foarstelde labels
+tagline = Bewarje artikelen en fideo’s fan Firefox út foar werjaan yn Pocket op ferskate apparaten, wannear dan ek.
+taglinestory_one = Klik op de Pocket-knop om artikelen, fideo’s of siden fan Firefox út te bewarjen.
+taglinestory_two = Besjoch se op ferskate apparaten, wannear dan ek.
+tagssaved = Labels tafoege
+tos = Troch fierder te gean, geane jo akkoard mei de <a href="%1$S" target="_blank">Tsjinstbetingsten</a> en it <a href="%2$S" target="_blank">Privacybelied</a> fan Pocket
+tryitnow = No probearje
+signinfirefox = Oanmelde mei Firefox
+signupfirefox = Registrearje mei Firefox
+viewlist = List werjaan
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Bewarje nei Pocket
+saveToPocketCmd.label = Side bewarje nei Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Keppeling bewarje nei Pocket
+saveLinkToPocketCmd.accesskey = e
+pocketMenuitem.label = Pocket-list werjaan
diff --git a/browser/extensions/pocket/locale/gu-IN/pocket.properties b/browser/extensions/pocket/locale/gu-IN/pocket.properties
new file mode 100644
index 000000000..2261ff5b4
--- /dev/null
+++ b/browser/extensions/pocket/locale/gu-IN/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = ટૅગ્સ ઉમેરો
+alreadyhaveacct = પહેલેથી જ એક પોકેટ વપરાશકર્તા છો?
+continueff = ફાયરફોક્સ સાથે ચાલુ રાખો
+errorgeneric = પોકેટ સાચવી રાખવા માટે પ્રયાસ હતો ત્યારે એક ભૂલ હતી.
+learnmore = વધુ શીખો
+loginnow = પ્રવેશ કરો
+maxtaglength = ટૅગ્સ 25 અક્ષરો સુધી મર્યાદિત છે
+mustbeconnected = તમે પોકેટ પર સેવ કરવા માટે ઇન્ટરનેટ સાથે જોડાયેલ હોવા જ જોઈએ. કૃપા કરીને તમારા જોડાણ તપાસ કરો અને ફરીથી પ્રયત્ન કરો.
+onlylinkssaved = માત્ર લિંક્સ સાચવી શકાય છે
+pagenotsaved = પૃષ્ઠ સાચવેલા નથી
+pageremoved = પૃષ્ઠ દૂર
+pagesaved = પોકેટ પર સાચવ્યું
+processingremove = પૃષ્ઠ દૂર કરી રહ્યા છીએ…
+processingtags = ટૅગ્સ ઉમેરી રહ્યું છે…
+removepage = પૃષ્ઠ દૂર
+save = સાચવો
+saving = સાચવી રહ્યું છે…
+signupemail = ઇમેઇલ સાથે સાઇનઅપ
+signuptosave = પોકેટ માટે સાઇન અપ કરો. તે મફત છે.
+suggestedtags = સૂચવેલ ટૅગ્સ
+tagline = કોઈપણ ઉપકરણ, કોઈ પણ સમય પર પોકેટ માં જોવા માટે ફાયરફોક્સ ના લેખો અને વીડિયો સાચવો.
+taglinestory_one = ફાયરફોક્સ એક લેખ, વિડિઓ અથવા પાનું સેવ કરવા પોકેટ બટન પર ક્લિક કરો.
+taglinestory_two = કોઈપણ ઉપકરણ, કોઈ પણ સમય પર પોકેટ માં જુઓ.
+tagssaved = ટૅગ્સ ઉમેર્યું
+tos = ચાલુ કરવાથી, તમે પોકેટ માટેની <a href="%1$S" target="_blank">સેવાની શરતો</a> અને <a href="%2$S" target="_blank">ગોપનીયતા નીતિ</a>સંમત થશો
+tryitnow = અત્યારે પ્રયાસ કરો
+signinfirefox = ફાયરફોક્સ સાથે ચાલુ રાખો
+signupfirefox = ફાયરફોક્સ સાથે સાઇન અપ કરો
+viewlist = યાદી જુઓ
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = પોકેટ
+pocket-button.tooltiptext = પોકેટ પર સાચવો
+saveToPocketCmd.label = પોકેટ પર પૃષ્ઠ સાચવો
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = પોકેટ પર લિંક સાચવો
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = જુઓ પોકેટની યાદી
diff --git a/browser/extensions/pocket/locale/hr/pocket.properties b/browser/extensions/pocket/locale/hr/pocket.properties
new file mode 100644
index 000000000..3b723499f
--- /dev/null
+++ b/browser/extensions/pocket/locale/hr/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Dodaj oznake
+alreadyhaveacct = Postojeći ste Pocket korisnik?
+continueff = Nastavite s Firefoxom
+errorgeneric = Došlo je do greške pri snimanju u Pocket.
+learnmore = Saznajte više
+loginnow = Prijava
+maxtaglength = Oznake su ograničene na 25 znakova
+mustbeconnected = Morate biti povezani na Internet da bi ste mogli snimiti u Pocket. Molimo vas da provjerite vašu vezu i pokušate ponovno.
+onlylinkssaved = Mogu se spremiti samo poveznice
+pagenotsaved = Stranica nije spremljena
+pageremoved = Stranica uklonjena
+pagesaved = Spremljeno u Pocket
+processingremove = Uklanjanje stranice…
+processingtags = Dodavanje oznaka…
+removepage = Ukloni stranicu
+save = Spremi
+saving = Spremanje…
+signupemail = Registracija s e-poštom
+signuptosave = Registrirajte se na Pocket. Besplatno je.
+suggestedtags = Predložene oznake
+tagline = Spremite članke, video snimke iz Firefoxa za prikaz u Pocketu, na bilo kojem uređaju, bilo kada.
+taglinestory_one = Kliknite na Pocket tipku da biste snimili bilo koji članak, video ili stranicu iz Firefoxa.
+taglinestory_two = Pregledajte u Pocketu na bilo kojem uređaju, bilo kada.
+tagssaved = Oznake dodane
+tos = Nastavljajući, prihvaćate Pocket <a href="%1$S" target="_blank">Uvjete pružanja usluge</a> i <a href="%2$S" target="_blank">Izjavu o privatnosti</a>
+tryitnow = Isprobajte odmah
+signinfirefox = Prijava s Firefoxom
+signupfirefox = Registracija s Firefoxom
+viewlist = Prikaži popis
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Spremi u Pocket
+saveToPocketCmd.label = Spremi stranicu u Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Spremi poveznicu u Pocket
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Prikaži Pocket popis
diff --git a/browser/extensions/pocket/locale/hsb/pocket.properties b/browser/extensions/pocket/locale/hsb/pocket.properties
new file mode 100644
index 000000000..a5f5583e7
--- /dev/null
+++ b/browser/extensions/pocket/locale/hsb/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Znački přidać
+alreadyhaveacct = Sće hižo wužiwar Pocket?
+continueff = Z Firefox pokročować
+errorgeneric = Při składowanju do Pocket je zmylk wustupił.
+learnmore = Dalše informacije
+loginnow = Přizjewić
+maxtaglength = Znački su na 25 znamješkow wobmjezowane
+mustbeconnected = Dyrbiće z internetom zwjazany być, zo byšće do Pocket składował. Prošu přepruwujće swój zwisk a spytajće hišće raz.
+onlylinkssaved = Jenož wotkazy dadźa so składować
+pagenotsaved = Strona njeje so składowała
+pageremoved = Strona je so wotstroniła
+pagesaved = Do Pocket składowany
+processingremove = Strona so wotstronja…
+processingtags = Znački so přidawaja…
+removepage = Stronu wotstronić
+save = Składować
+saving = Składuje so…
+signupemail = Registrujće so z e-mejlku
+signuptosave = Registrujće so za Pocket. Je darmo.
+suggestedtags = Namjetowane znački
+tagline = Składujće nastawki a wideja z Firefox, zo byšće sej je kóždy čas w Pocket na kóždym graće wobhladał.
+taglinestory_one = Klikńće na tłóčatko Pocket, zo byšće nastawk, widejo abo stronu z Firefox składował.
+taglinestory_two = Sej w Pocket na kóždym graće kóždy čas wobhladać.
+tagssaved = Znački su so přidali
+tos = Hdyž pokročujeće, zwoliće do <a href="%1$S" target="_blank">wužiwarskich wuměnjenjow</a> a <a href="%2$S" target="_blank">prawidłow priwatnosće</a> Pocket
+tryitnow = Spytajće to nětko
+signinfirefox = Z Firefox přizjewić
+signupfirefox = Z Firefox registrować
+viewlist = Lisćinu pokazać
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Do Pocket składować
+saveToPocketCmd.label = Stronu do Pocket składować
+saveToPocketCmd.accesskey = d
+saveLinkToPocketCmd.label = Wotkaz do Pocket składować
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Lisćinu Pocket pokazać
diff --git a/browser/extensions/pocket/locale/hu/pocket.properties b/browser/extensions/pocket/locale/hu/pocket.properties
new file mode 100644
index 000000000..767638e82
--- /dev/null
+++ b/browser/extensions/pocket/locale/hu/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Címkék hozzáadása
+alreadyhaveacct = Már Pocket felhasználó?
+continueff = Folytatás a Firefoxszal
+errorgeneric = Hiba történt a Pocketre mentés közben.
+learnmore = Tudjon meg többet
+loginnow = Bejelentkezés
+maxtaglength = A címkék legfeljebb 25 karakter hosszúak lehetnek
+mustbeconnected = Csatlakoznia kell az internethez a Pocketre mentéshez. Ellenőrizze a kapcsolatot, és próbálja újra.
+onlylinkssaved = Csak hivatkozások menthetők
+pagenotsaved = Az oldal nem lett mentve
+pageremoved = Oldal eltávolítva
+pagesaved = Mentve a Pocketbe
+processingremove = Oldal eltávolítása…
+processingtags = Címkék hozzáadása…
+removepage = Oldal eltávolítása
+save = Mentés
+saving = Mentés…
+signupemail = Regisztráció e-maillel
+signuptosave = Regisztráljon ingyenesen a Pocketre.
+suggestedtags = Javasolt címkék
+tagline = Mentsen cikkeket és videókat a Firefoxból a Pocketen való megtekintéshez bármely eszközön, bármikor.
+taglinestory_one = Kattintson a Pocket gombra bármely cikk, videó vagy oldal mentéséhez a Firefoxból.
+taglinestory_two = Nézze meg a Pocketen bármely eszközön, bármikor.
+tagssaved = Címkék hozzáadva
+tos = A folytatással elfogadja a Pocket <a href="%1$S" target="_blank">Szolgáltatási feltételeit</a> és az <a href="%2$S" target="_blank">Adatvédelmi nyilatkozatot</a>
+tryitnow = Próbálja ki most
+signinfirefox = Bejelentkezés a Firefoxszal
+signupfirefox = Regisztráció a Firefoxszal
+viewlist = Lista megjelenítése
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Mentés a Pocketbe
+saveToPocketCmd.label = Oldal mentése a Pocketbe
+saveToPocketCmd.accesskey = c
+saveLinkToPocketCmd.label = Hivatkozás mentése a Pocketbe
+saveLinkToPocketCmd.accesskey = H
+pocketMenuitem.label = Pocket lista megjelenítése
diff --git a/browser/extensions/pocket/locale/it/pocket.properties b/browser/extensions/pocket/locale/it/pocket.properties
new file mode 100644
index 000000000..2105011eb
--- /dev/null
+++ b/browser/extensions/pocket/locale/it/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Aggiungi etichette
+alreadyhaveacct = Hai già un account registrato su Pocket?
+continueff = Prosegui con Firefox
+errorgeneric = Si è verificato un errore durante il salvataggio in Pocket.
+learnmore = Ulteriori informazioni
+loginnow = Accedi
+maxtaglength = La lunghezza massima per le etichette è di 25 caratteri
+mustbeconnected = È necessario essere connessi a Internet per salvare in Pocket. Verificare la connessione e riprovare.
+onlylinkssaved = È possibile salvare solo link
+pagenotsaved = Pagina non salvata
+pageremoved = Pagina rimossa
+pagesaved = Salvata in Pocket
+processingremove = Rimozione pagina…
+processingtags = Salvataggio etichette…
+removepage = Rimuovi pagina
+save = Salva
+saving = Salvataggio…
+signupemail = Accedi con email
+signuptosave = Registrati su Pocket. È gratis.
+suggestedtags = Etichette suggerite
+tagline = Salva articoli e video da Firefox per visualizzarli in Pocket da qualunque dispositivo e in qualunque momento.
+taglinestory_one = Fai clic sul pulsante Pocket per salvare qualunque articolo, video o pagina da Firefox.
+taglinestory_two = Visualizza in Pocket da qualunque dispositivo e in qualunque momento.
+tagssaved = Aggiunte etichette
+tos = Proseguendo si accettano i <a href="%1$S" target="_blank">termini di servizio</a> e l’<a href="%2$S" target="_blank">informativa sulla privacy</a>
+tryitnow = Provalo subito
+signinfirefox = Accedi con Firefox
+signupfirefox = Registrati con Firefox
+viewlist = Visualizza elenco
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Salva in Pocket
+saveToPocketCmd.label = Salva pagina in Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Salva link in Pocket
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Visualizza elenco Pocket
diff --git a/browser/extensions/pocket/locale/ja/pocket.properties b/browser/extensions/pocket/locale/ja/pocket.properties
new file mode 100644
index 000000000..1aef6bba1
--- /dev/null
+++ b/browser/extensions/pocket/locale/ja/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = タグを追加
+alreadyhaveacct = Pocket に登録済みですか?
+continueff = Firefox で続行
+errorgeneric = Pocket への保存中にエラーがありました。
+learnmore = 詳細
+loginnow = ログイン
+maxtaglength = タグは 25 文字までです
+mustbeconnected = Pocket に保存するには、インターネット接続が必要です。接続状況を確認してから、試してみたください。
+onlylinkssaved = リンクのみ保存しました
+pagenotsaved = ページを保存しませんでした
+pageremoved = ページを削除しました
+pagesaved = Pocket に保存しました
+processingremove = ページを削除しています...
+processingtags = タグを追加しています...
+removepage = ページを削除
+save = 保存
+saving = 保存しています...
+signupemail = メールアドレスで新規登録
+signuptosave = Pocket に新規登録します。無料です。
+suggestedtags = 提案タグ
+tagline = Firefox で記事や動画を保存すると、いつでもどこでも Pocket で閲覧できます。
+taglinestory_one = Firefox で Pocket ボタンをクリックすると、様々な記事や動画やページを保存できます。
+taglinestory_two = Pocket でいつでもどこでも閲覧できます。
+tagssaved = タグを追加しました
+tos = 続けることで、Pocket の <a href="%1$S" target="_blank">利用規約</a> と <a href="%2$S" target="_blank">プライバシーポリシー</a> に同意したことになります
+tryitnow = 今すぐ試す
+signinfirefox = Firefox でログイン
+signupfirefox = Firefox で新規登録
+viewlist = リストを表示
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Pocket に保存
+saveToPocketCmd.label = ページを Pocket に保存
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = リンクを Pocket に保存
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Pocket のリストを表示
diff --git a/browser/extensions/pocket/locale/jar.mn b/browser/extensions/pocket/locale/jar.mn
new file mode 100644
index 000000000..f29ca7367
--- /dev/null
+++ b/browser/extensions/pocket/locale/jar.mn
@@ -0,0 +1,33 @@
+#filter substitution
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+# These are used for the big if statement, as the preprocessor can't handle
+# dashes.
+#define bn_BD bn-BD
+#define en_GB en-GB
+#define en_US en-US
+#define es_AR es-AR
+#define es_CL es-CL
+#define es_ES es-ES
+#define es_MX es-MX
+#define fy_NL fy-NL
+#define gu_IN gu-IN
+#define nn_NO nn-NO
+#define pt_BR pt-BR
+#define pt_PT pt-PT
+#define sv_SE sv-SE
+#define zh_CN zh-CN
+#define zh_TW zh-TW
+
+[features/firefox@getpocket.com] @AB_CD@.jar:
+% locale pocket @AB_CD@ %locale/@AB_CD@/
+ # For locales we support, include the file from the locale's directory in the
+ # source tree.
+ # For other locales (and en-US) fallback to the en-US directory.
+#if AB_CD == ast || AB_CD == az || AB_CD == bg || AB_CD == bn_BD || AB_CD == cs || AB_CD == da || AB_CD == de || AB_CD == dsb || AB_CD == en_GB || AB_CD == en_US || AB_CD == es_AR || AB_CD == es_CL || AB_CD == es_ES || AB_CD == es_MX || AB_CD == et || AB_CD == fi || AB_CD == fr || AB_CD == fy_NL || AB_CD == gu_IN || AB_CD == hr || AB_CD == hsb || AB_CD == hu || AB_CD == it || AB_CD == ja || AB_CD == ka || AB_CD == kab || AB_CD == lt || AB_CD == lv || AB_CD == mr || AB_CD == ms || AB_CD == nl || AB_CD == nn_NO || AB_CD == or || AB_CD == pl || AB_CD == pt_BR || AB_CD == pt_PT || AB_CD == rm || AB_CD == ro || AB_CD == ru || AB_CD == sk || AB_CD == sl || AB_CD == sq || AB_CD == sr || AB_CD == sv_SE || AB_CD == te || AB_CD == th || AB_CD == tr || AB_CD == uk || AB_CD == zh_CN || AB_CD == zh_TW
+ locale/@AB_CD@/ (@AB_CD@/*)
+#else
+ locale/@AB_CD@/ (en-US/*)
+#endif
diff --git a/browser/extensions/pocket/locale/ka/pocket.properties b/browser/extensions/pocket/locale/ka/pocket.properties
new file mode 100644
index 000000000..266ded044
--- /dev/null
+++ b/browser/extensions/pocket/locale/ka/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = იარლიყების დამატება
+alreadyhaveacct = უკვე იყენებთ Pocket-ს?
+continueff = Firefox-ით გაგრძელება
+errorgeneric = Pocket-ში შენახვისას დაფიქსირდა შეცდომა.
+learnmore = დაწვრილებით
+loginnow = შესვლა
+maxtaglength = იარლიყები შეზღუდულია 25 ასომდე
+mustbeconnected = Pocket-ში შესანახად საჭიროა ინტერნეთთან კავშირი. გთხოვთ შეამოწმეთ თქვენი კავშირი და ხელახლა ცადეთ.
+onlylinkssaved = შესაძლებელია მხოლოდ ბმულების შენახვა
+pagenotsaved = გვერდი არ შეინახა
+pageremoved = გვერდი წაიშალა
+pagesaved = შეინახა Pocket-ში
+processingremove = იშლება გვერდი…
+processingtags = ემატება იარლიყები…
+removepage = გვერდის წაშლა
+save = შენახვა
+saving = ინახება…
+signupemail = რეგისტრაცია ელ-ფოსტით
+signuptosave = დარეგისტრირდით Pocket-ზე. ეს უფასოა.
+suggestedtags = შემოთავაზებული იარლიყები
+tagline = შეინახეთ სტატიები და ვიდეობეი Firefox-იდან მათ Pocket-ში სანახავად ნებისმიერ მოწყობილობაზე, ნებისმიერ დროს.
+taglinestory_one = Firefox-იდან ნებისმიერი სტატიის, ვიდეოს ან გვერდის შესანახად დააწკაპეთ Pocket-ის ღილაკს.
+taglinestory_two = დაათვალიერეთ Pocket-ში ნებისმიერ მოწყობილობაზე, ნებისმიერ დროს.
+tagssaved = იარლიყები დაემატა
+tos = გაგრძელების შემთხვევაში თქვენ ეთანხმებით Pocket-ის <a href="%1$S" target="_blank">მომსახურების პირობებს</a> და <a href="%2$S" target="_blank">პრივატულობის პოლიტიკას</a>
+tryitnow = სცადეთ ახლავე
+signinfirefox = შესვლა Firefox-ით
+signupfirefox = რეგისრაცია Firefox-ით
+viewlist = სიის ნახვა
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Pocket-ში შენახვა
+saveToPocketCmd.label = გვერდის შენახვა Pocket-ში
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = ბმულის შენახვა Pocket-ში
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Pocket სიის ნახვა
diff --git a/browser/extensions/pocket/locale/kab/pocket.properties b/browser/extensions/pocket/locale/kab/pocket.properties
new file mode 100644
index 000000000..3f4cc642a
--- /dev/null
+++ b/browser/extensions/pocket/locale/kab/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Rnu tibzimin
+alreadyhaveacct = Aseqdac yakan n Pocket?
+continueff = Kemmel s Firefox
+errorgeneric = Teḍra-d tuccḍa deg aɛraḍ n usekles ɣer Pocket.
+learnmore = Issin ugar
+loginnow = Kcem
+maxtaglength = Tibzimin ɣur-sent talast n 25 n isekkilen
+mustbeconnected = Yessefk ad tiliḍ teqqneḍ ɣer Internet akken ad tizmireḍ ad teskelseḍ ɣer Pocket. Ma ulac aɣilif, senqed tuqqna yinek sakin ɛreḍ tikelt nniḍen.
+onlylinkssaved = Al iseɣwan i yezmren ad ttwakelsen
+pagenotsaved = Asebter ur yettwakles ara
+pageremoved = Asebter yettwakkes
+pagesaved = Yettwakles ɣer Pocket
+processingremove = Tukksa n isebtar…
+processingtags = Timerna n tebzimin…
+removepage = Kkes asebter
+save = Sekles
+saving = Asekles…
+signupemail = Jerred s yimayl
+signuptosave = Jerred ɣer Pocket. Baṭel.
+suggestedtags = Tibzimin yettwasumren
+tagline = Sekles imagraden akked tvidyutin si Firefox akken ad twaliḍ di Pocket ɣef yal ibenk, melmi tebɣiḍ.
+taglinestory_one = Sit ɣef tqeffalt Pocket akken ad teskelseḍ yal amagrad, tavidyut neɣ asebter si Firefox.
+taglinestory_two = Sken di Pocket ɣef yal ibenk yellan, melmi tebɣiḍ.
+tagssaved = Tibzimin yettwarnan
+tos = Ma tkemleḍ, ad tqebleḍ <a href="%1$S" target="_blank">tiwtilin n useqdec</a> akked <a href="%2$S" target="_blank">tsertit tabaḍnit</a> n Pocket
+tryitnow = Ɛreḍ-it tura
+signinfirefox = Kcem s Firefox
+signupfirefox = Jerred s Firefox
+viewlist = Sken tabdart
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Sekles ɣer Pocket
+saveToPocketCmd.label = Sekles asebter ɣer Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Sekles aseɣwen ɣer Pocket
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Sken tabdart n Pocket
diff --git a/browser/extensions/pocket/locale/lt/pocket.properties b/browser/extensions/pocket/locale/lt/pocket.properties
new file mode 100644
index 000000000..f3e8df077
--- /dev/null
+++ b/browser/extensions/pocket/locale/lt/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Pridėkite gairių
+alreadyhaveacct = Jau naudojatės „Pocket“?
+continueff = Tęsti su „Firefox“
+errorgeneric = Bandant išsaugoti į „Pocket“ įvyko klaida.
+learnmore = Sužinokite daugiau
+loginnow = Prisijungti
+maxtaglength = Gaires gali sudaryti iki 25 simbolių
+mustbeconnected = Norėdami saugoti į „Pocket“, turite būti prisijungę prie interneto. Prašome patikrinti savo ryšį ir bandyti vėl.
+onlylinkssaved = Išsaugoti galima tik nuorodas
+pagenotsaved = Tinklalapis neišsaugotas
+pageremoved = Tinklalapis pašalintas
+pagesaved = Išsaugota į „Pocket“
+processingremove = Šalinamas tinklalapis…
+processingtags = Pridedamos gairės…
+removepage = Pašalinti tinklalapį
+save = Išsaugoti
+saving = Išsaugoma…
+signupemail = Prisijungti su el. paštu
+signuptosave = Pradėkite naudotis „Pocket“. Tai nemokama.
+suggestedtags = Siūlomos gairės
+tagline = Išsaugokite straipsnius bei vaizdo įrašus iš „Firefox“ norėdami juos peržiūrėti bet kokiame įrenginyje su „Pocket“, bet kuriuo metu.
+taglinestory_one = Spustelėkite „Pocket“ mygtuką norėdami išsaugoti bet kokį straipsnį, vaizdo įrašą ar tinklalapį iš „Firefox“.
+taglinestory_two = Peržiūrėkite bet kokiame įrenginyje su „Pocket“, bet kuriuo metu.
+tagssaved = Gairės pridėtos
+tos = Tęsdami sutinkate su „Pocket“ <a href="%1$S" target="_blank">paslaugos teikimo sąlygomis</a> bei <a href="%2$S" target="_blank">privatumo nuostatais</a>
+tryitnow = Išbandykite dabar
+signinfirefox = Prisijungti su „Firefox“
+signupfirefox = Prisijungti su „Firefox“
+viewlist = Peržiūrėti sąrašą
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Išsaugoti į „Pocket“
+saveToPocketCmd.label = Išsaugoti tinklalapį į „Pocket“
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Išsaugoti saitą į „Pocket“
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Peržiūrėti „Pocket“ sąrašą
diff --git a/browser/extensions/pocket/locale/lv/pocket.properties b/browser/extensions/pocket/locale/lv/pocket.properties
new file mode 100644
index 000000000..40e3bb367
--- /dev/null
+++ b/browser/extensions/pocket/locale/lv/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Pievienot birkas
+alreadyhaveacct = Jau lietojat Pocket?
+continueff = Turpināt ar Firefox
+errorgeneric = Kļūda saglabājot Pocket.
+learnmore = Uzzināt vairāk
+loginnow = Pieslēgties
+maxtaglength = Birkas nevar būt garākas par 25 simboliem
+mustbeconnected = Lai saglabātu Pocket, jābūt savienojumam ar internetu. Lūdzu pārbaudiet savienojumu un mēģiniet vēlreiz.
+onlylinkssaved = Saglabāt var tikai saites
+pagenotsaved = Lapa nav saglabāta
+pageremoved = Lapa ir aizvākta
+pagesaved = Saglabāt Pocket
+processingremove = Aizvāc lapu…
+processingtags = Pievieno birkas…
+removepage = Izņemt lapu
+save = Saglabāt
+saving = Saglabā…
+signupemail = Pierakstīties ar epastu
+signuptosave = Pierakstīties Pocket. Tas ir bez maksas.
+suggestedtags = Ieteiktās birkas
+tagline = Saglabājiet Firefox rakstu vai video, lai skatītos to ar Pocket jebkurā ierīcē un jebkurā laikā.
+taglinestory_one = Klikšķiniet uz Pocket pogas, lai saglabātu Firefox rakstus, video vai lapas.
+taglinestory_two = Skatiet ar Pocket jebkurā ierīcē un jebkurā laikā.
+tagssaved = Birkas pievienotas
+tos = Turpinot, tu piekrīti Pocket <a href="%1$S" target="_blank">Noteikumiem</a> un <a href="%2$S" target="_blank">Privātuma politikai</a>
+tryitnow = Izmēģini tagad
+signinfirefox = Pieslēgties ar Firefox
+signupfirefox = Pierakstīties ar Firefox
+viewlist = Skatījumu saraksts
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Saglabāt Pocket
+saveToPocketCmd.label = Saglabāt lapu Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Saglabāt saiti Pocket
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Aplūkot Pocket sarakstu
diff --git a/browser/extensions/pocket/locale/moz.build b/browser/extensions/pocket/locale/moz.build
new file mode 100644
index 000000000..aac3a838c
--- /dev/null
+++ b/browser/extensions/pocket/locale/moz.build
@@ -0,0 +1,7 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+JAR_MANIFESTS += ['jar.mn']
diff --git a/browser/extensions/pocket/locale/mr/pocket.properties b/browser/extensions/pocket/locale/mr/pocket.properties
new file mode 100644
index 000000000..af330ec1e
--- /dev/null
+++ b/browser/extensions/pocket/locale/mr/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = टॅग जोडा
+alreadyhaveacct = आधीपासून Pocket वापरताय?
+continueff = Firefox सोबत पुढे चला
+errorgeneric = Pocket मध्ये जतन करताना त्रुटी आली.
+learnmore = अधिक जाणून घ्या
+loginnow = लॉग इन
+maxtaglength = टॅग्ज साठी 25 वर्णांची मर्यादा आहे
+mustbeconnected = Pocket मध्ये साठविण्यासाठी आपले इंटरनेट चालू असणे आवश्यक आहे. कृपया आपली जोडणी तपासा आणि पुन्हा प्रयत्न करा.
+onlylinkssaved = फक्त दुवे जतन केले जाऊ शकतात
+pagenotsaved = पृष्ठ जतन झाले नाही
+pageremoved = पृष्ठ काढले गेले
+pagesaved = Pocket मध्ये जतन झाले
+processingremove = पृष्ठ काढून टाकत आहे...
+processingtags = टॅग्ज जोडत आहे…
+removepage = पृष्ठ काढून टाका
+save = जतन करा
+saving = जतन करत आहे...
+signupemail = ईमेलसह साईन अप करा
+signuptosave = Pocket साठी साईन अप करा. हे मोफत आहे.
+suggestedtags = सूचविलेले टॅग्स
+tagline = Firefox मधील नोंदी आणि व्हिडीओ कुठल्याही साधनावर केंव्हाही Pocket मध्ये पाहण्यासाठी साठवा.
+taglinestory_one = Firefox वरील कोणताही लेख, व्हिडिओ किंवा पृष्ठ जतन करण्यासाठी Pocket बटणावर क्लिक करा.
+taglinestory_two = कधीही कुठल्याही साधनावर Pocket मध्ये पाहा.
+tagssaved = टॅग्स जोडले
+tos = सुरु ठेवुन, आपण Pocketच्या <a href="%1$S" target="_blank">सेवेच्या अटी</a> आणि <a href="%2$S" target="_blank">गोपनीयता धोरणांशी</a> सहमत आहात
+tryitnow = आत्ताच वापरुन पाहा
+signinfirefox = Firefox सह साइन इन करा
+signupfirefox = Firefox सह साईन अप करा
+viewlist = यादी पहा
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Pocket मध्ये जतन करा
+saveToPocketCmd.label = पृष्ठ Pocket मध्ये जतन करा
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = दुवा Pocket मध्ये संकलित करा
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = पॉकेट सूची पहा
diff --git a/browser/extensions/pocket/locale/ms/pocket.properties b/browser/extensions/pocket/locale/ms/pocket.properties
new file mode 100644
index 000000000..67a935be8
--- /dev/null
+++ b/browser/extensions/pocket/locale/ms/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Tambah Tag
+alreadyhaveacct = Sudah menjadi pengguna Poket?
+continueff = Teruskan dengan Firefox
+errorgeneric = Ada ralat semasa cuba menyimpan ke Pocket.
+learnmore = Ketahui Selanjutnya
+loginnow = Log masuk
+maxtaglength = Tag dihadkan hanya 25 aksara
+mustbeconnected = Anda mesti ada sambungan Internet untuk menyimpan ke Pocket. Sila periksa sambungan anda dan cuba lagi.
+onlylinkssaved = Hanya pautan boleh disimpan
+pagenotsaved = Halaman Tidak Disimpan
+pageremoved = Halaman Dialih keluar
+pagesaved = Disimpan ke Pocket
+processingremove = Sedang mengalih keluar Halaman…
+processingtags = Sedang menambah tag…
+removepage = Alih keluar Halaman
+save = Simpan
+saving = Sedang menyimpan…
+signupemail = Daftar dengan e-mel
+signuptosave = Daftar masuk ke Pocket. Percuma.
+suggestedtags = Tag Disyorkan
+tagline = Simpan artikel dan video dari Firefox untuk dilihat dalam Pocket pada apa jua peranti pada bila-bila masa.
+taglinestory_one = Klik butang Pocket untuk menyimpan apa jua artikel, video atau halaman daripada Firefox.
+taglinestory_two = Papar dalam Pocket dalam mana-mana peranti, bila-bila masa saja.
+tagssaved = Tag Ditambah
+tos = Dengan meneruskan, anda setuju dengan <a href="%1$S" target="_blank">Terma Perkhidmatan</a> Pocket dan <a href="%2$S" target="_blank">Polisi Privasi</a>
+tryitnow = Cubanya Sekarang
+signinfirefox = Daftar masuk Firefox
+signupfirefox = Daftar dengan Firefox
+viewlist = Senarai Paparan
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Simpan ke Pocket
+saveToPocketCmd.label = Simpan Halaman ke Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Simpan Pautan ke Pocket
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Papar Senarai Pocket
diff --git a/browser/extensions/pocket/locale/nl/pocket.properties b/browser/extensions/pocket/locale/nl/pocket.properties
new file mode 100644
index 000000000..3abe14491
--- /dev/null
+++ b/browser/extensions/pocket/locale/nl/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Labels toevoegen
+alreadyhaveacct = Al een Pocket-gebruiker?
+continueff = Doorgaan met Firefox
+errorgeneric = Er is een fout opgetreden bij het opslaan naar Pocket.
+learnmore = Meer info
+loginnow = Meld u aan
+maxtaglength = Labels zijn beperkt tot 25 tekens
+mustbeconnected = U moet met het internet zijn verbonden om naar Pocket te kunnen opslaan. Controleer uw verbinding en probeer het opnieuw.
+onlylinkssaved = Alleen koppelingen kunnen worden opgeslagen
+pagenotsaved = Pagina niet opgeslagen
+pageremoved = Pagina verwijderd
+pagesaved = Opgeslagen naar Pocket
+processingremove = Pagina verwijderen…
+processingtags = Labels toevoegen…
+removepage = Pagina verwijderen
+save = Opslaan
+saving = Opslaan…
+signupemail = Registreren met e-mailadres
+signuptosave = Registreer voor Pocket. Het is gratis.
+suggestedtags = Voorgestelde labels
+tagline = Sla artikelen en video’s vanuit Firefox op voor weergeven in Pocket op diverse apparaten, wanneer dan ook.
+taglinestory_one = Klik op de Pocket-knop om artikelen, video’s of pagina’s vanuit Firefox op te slaan.
+taglinestory_two = Bekijk ze op diverse apparaten, wanneer dan ook.
+tagssaved = Labels toegevoegd
+tos = Door verder te gaan, gaat u akkoord met de <a href="%1$S" target="_blank">Servicevoorwaarden</a> en het <a href="%2$S" target="_blank">Privacybeleid</a> van Pocket
+tryitnow = Nu proberen
+signinfirefox = Aanmelden met Firefox
+signupfirefox = Registreren met Firefox
+viewlist = Lijst weergeven
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Opslaan naar Pocket
+saveToPocketCmd.label = Pagina opslaan naar Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Koppeling opslaan naar Pocket
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Pocket-lijst weergeven
diff --git a/browser/extensions/pocket/locale/nn-NO/pocket.properties b/browser/extensions/pocket/locale/nn-NO/pocket.properties
new file mode 100644
index 000000000..3f3dc971e
--- /dev/null
+++ b/browser/extensions/pocket/locale/nn-NO/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Legg til merkelapp-stikkord
+alreadyhaveacct = Allereie ein Pocket-brukar?
+continueff = Hald fram med Firefox
+errorgeneric = Eit problem oppstod ved lagring til Pocket.
+learnmore = Les meir
+loginnow = Logg inn
+maxtaglength = Merkelapp-stikkord er avgrensa til 25 teikn
+mustbeconnected = Du må vera kopla til nettet for å lagra til Pocket. Kontroller tilkoplinga og prøv igjen.
+onlylinkssaved = Berre lenker kan lagrast
+pagenotsaved = Sida ikkje lagra
+pageremoved = Sida fjerna
+pagesaved = Lagrar til Pocket
+processingremove = Fjernar sida …
+processingtags = Legg til merkelapp-stikkord…
+removepage = Fjern sida
+save = Lagra
+saving = Lagrar …
+signupemail = Logg inn med e-postadresse
+signuptosave = Registrer deg på Pocket. Det er gratis.
+suggestedtags = Føreslåtte merkelapp-stikkord
+tagline = Lagra artiklar og videoar frå Firefox for å visa dei i Pocket på kva som helst eining, når som helst.
+taglinestory_one = Trykk på Pocket-knappen for å lagra kva som helst artikkel, video eller side frå Firefox.
+taglinestory_two = Vis i Pocket, på kva som helst eining, når som helst.
+tagssaved = Merkelapp-stikkord lagt til
+tos = Ved å fortsetta godtek du Pocket sine <a href="%1$S" target="_blank">tenestevilkår</a> og <a href="%2$S" target="_blank">personvernpraksis</a>
+tryitnow = Prøv no
+signinfirefox = Logg inn med Firefox
+signupfirefox = Registrer deg med Firefox
+viewlist = Vis liste
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Lagra til Pocket
+saveToPocketCmd.label = Lagra sida i Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Lagra lenke til Pocket
+saveLinkToPocketCmd.accesskey = l
+pocketMenuitem.label = Vis Pocket-liste
diff --git a/browser/extensions/pocket/locale/or/pocket.properties b/browser/extensions/pocket/locale/or/pocket.properties
new file mode 100644
index 000000000..d2616e484
--- /dev/null
+++ b/browser/extensions/pocket/locale/or/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = ଟ୍ୟାଗ ଯୋଡ଼ନ୍ତୁ
+alreadyhaveacct = ଆଗରୁ Pocket ବ୍ୟବହାର କରୁଛନ୍ତି?
+continueff = Firefox ଦେଇ ଆଗକୁ ଯିବେ
+errorgeneric = Pocketରେ ସାଇତିବା ବେଳେ ଅସୁବିଧାଟିଏ ହେଲା ।
+learnmore = ଅଧିକ ଶିଖନ୍ତୁ
+loginnow = ଲଗ ଇନ
+maxtaglength = ଟ୍ୟାଗ 25 ଟି ଅକ୍ଷରରେ ସୀମିତ
+mustbeconnected = Pocketରେ ସାଇତିବା ପାଇଁ ଆପଣ ଇଣ୍ଟରନେଟ ସହ ସଂଯୁକ୍ତ ହୋଇଥିବା ଲୋଡ଼ା । ଦୟାକରି ନିଜ ସଂଯୋଗ ପରଖି ଆଉଥରେ ଚେଷ୍ଟାକରନ୍ତୁ ।
+onlylinkssaved = କେବଳ ଲିଙ୍କ ସାଇତାଯାଇପାରିବ
+pagenotsaved = ପୃଷ୍ଠା ସାଇତା ଯାଇନାହିଁ
+pageremoved = ପୃଷ୍ଠାଟି ହଟାଗଲା
+pagesaved = Pocketରେ ସାଇତାଗଲା
+processingremove = ପୃଷ୍ଠା ହଟାଯାଉଛି…
+processingtags = ଟ୍ୟାଗ ଯୋଡ଼ାଯାଉଛି…
+removepage = ପୃଷ୍ଠା ହଟାନ୍ତୁ
+save = ସାଇତିବେ
+saving = ସାଇତୁଛି…
+signupemail = ଇମେଲରେ ସାଇନ ଅପ
+signuptosave = Pocket ପାଇଁ ସାଇନ ଅପ । ଏହା ମାଗଣା ।
+suggestedtags = ପ୍ରସ୍ତାବିତ ଟ୍ୟାଗ
+tagline = ଯେତେବେଳେ ଲୋଡ଼ା କୌଣସି ଏକ ଡିଭାଇସରୁ Pocketରେ ଦେଖିବା ପାଇଁ Firefoxରୁ ପ୍ରସଙ୍ଗ ଓ ଭିଡ଼ିଓ ସାଇତିପାରିବେ ।
+taglinestory_one = କୌଣସି ପ୍ରସଙ୍ଗ, ଭିଡ଼ିଓ ବା ପୃଷ୍ଠା ସାଇତିବା ପାଇଁ Pocket Button ଟିପନ୍ତୁ ।
+taglinestory_two = ଯେତେବେଳେ ଲୋଡ଼ା ସବୁ ଡିଭାଇସରୁ Pocketରେ ଦେଖନ୍ତୁ ।
+tagssaved = ଟ୍ୟାଗ ଯୋଡ଼ାଗଲା
+tos = ଆଗକୁ ବଢ଼ିବା ଯୋଗୁ ଆପଣ Pocketର <a href="%1$S" target="_blank">ନୀତି ନିୟମ</a> ଓ <a href="%2$S" target="_blank">ଗୋପନୀୟତା ନୀତିବଳୀ</a> ମାନୁଛନ୍ତି ବୋଲି ଜାଣିରଖିବେ
+tryitnow = ଏବେ ଏହା ଚେଷ୍ଟାକରନ୍ତୁ
+signinfirefox = Firefoxରେ ସାଇନ ଇନ କରନ୍ତୁ
+signupfirefox = Firefoxରେ ସାଇନ ଅପ କରନ୍ତୁ
+viewlist = ତାଲିକା ଦେଖନ୍ତୁ
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Pocketରେ ସାଇତନ୍ତୁ
+saveToPocketCmd.label = Pocketରେ ପୃଷ୍ଠା ସାଇତନ୍ତୁ
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Pocketରେ ଲିଙ୍କ ସାଇତନ୍ତୁ
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Pocket ତାଲିକା ଦେଖନ୍ତୁ
diff --git a/browser/extensions/pocket/locale/pl/pocket.properties b/browser/extensions/pocket/locale/pl/pocket.properties
new file mode 100644
index 000000000..07b5866f1
--- /dev/null
+++ b/browser/extensions/pocket/locale/pl/pocket.properties
@@ -0,0 +1,48 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+taglinestory_one=Kliknij przycisk Pocket, aby wysłać dowolny artykuł, film lub stronę z Firefoksa.
+taglinestory_two=Czytaj z Pocket o dowolnej porze na dowolnym urządzeniu.
+learnmore=Więcej informacji
+
+signuptosave=Utwórz konto w Pocket. Jest darmowe.
+signupfirefox=Utwórz konto z Firefoksem
+signupemail=Utwórz konto z adresem e-mail
+alreadyhaveacct=Masz już konto Pocket?
+loginnow=Zaloguj się
+
+tos=Kontynuując, wyrażasz zgodę na <a href="%1$S" target="_blank">warunki korzystania z usługi</a> i <a href="%2$S" target="_blank">politykę prywatności</a>
+tryitnow=Wypróbuj teraz
+
+continueff=Kontynuuj z kontem Firefoksa
+signinfirefox=Zaloguj się z Firefoksem
+viewlist=Otwórz w Pocket
+
+removepage=Usuń stronę
+processingremove=Usuwanie strony…
+pageremoved=Usunięto stronę
+
+save=Wyślij
+saving=Wysyłanie…
+pagesaved=Wysłano do Pocket
+
+addtags=Etykiety
+processingtags=Wysyłanie etykiet…
+tagssaved=Wysłano etykiety
+maxtaglength=Etykiety są ograniczone do 25 znaków
+suggestedtags=Sugerowane etykiety
+tagline=Wysyłaj artykuły i filmy z Firefoksa do Pocket, aby wyświetlić je o dowolnej porze na dowolnym urządzeniu.
+
+errorgeneric=Wystąpił błąd podczas wysyłania do Pocket.
+mustbeconnected=Połączenie z Internetem jest konieczne do przesyłania do Pocket. Proszę sprawdzić połączenie i spróbować ponownie.
+onlylinkssaved=Tylko odnośniki mogą być przesyłane
+pagenotsaved=Nie przesłano strony
+
+pocket-button.label=Pocket
+pocket-button.tooltiptext=Wyślij do Pocket
+saveToPocketCmd.label=Wyślij stronę do Pocket
+saveToPocketCmd.accesskey=s
+saveLinkToPocketCmd.label=Wyślij odnośnik do Pocket
+saveLinkToPocketCmd.accesskey=o
+pocketMenuitem.label=Wysłane do Pocket
diff --git a/browser/extensions/pocket/locale/pt-BR/pocket.properties b/browser/extensions/pocket/locale/pt-BR/pocket.properties
new file mode 100644
index 000000000..a637aea29
--- /dev/null
+++ b/browser/extensions/pocket/locale/pt-BR/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Adicionar etiquetas
+alreadyhaveacct = Já é um usuário do Pocket?
+continueff = Continuar com o Firefox
+errorgeneric = Houve um erro ao tentar salvar no Pocket.
+learnmore = Saber mais
+loginnow = Entrar
+maxtaglength = As etiquetas estão limitadas a 25 caracteres
+mustbeconnected = Você deve estar conectado à Internet para salvar no Pocket. Verifique a sua conexão e tente novamente.
+onlylinkssaved = Somente links podem ser salvos
+pagenotsaved = Página não salva
+pageremoved = Página removida
+pagesaved = Salva no Pocket
+processingremove = Removendo página…
+processingtags = Adicionando etiquetas…
+removepage = Remover página
+save = Salvar
+saving = Salvando…
+signupemail = Registrar com e-mail
+signuptosave = Registre-se no Pocket. É gratuito.
+suggestedtags = Etiquetas sugeridas
+tagline = Salve os artigos e vídeos do Firefox no Pocket para vê-los mais tarde e em qualquer local.
+taglinestory_one = Clique no botão Pocket para salvar um artigo, vídeo ou página do Firefox.
+taglinestory_two = Ver no Pocket em qualquer dispositivo, a qualquer hora.
+tagssaved = Etiquetas adicionadas
+tos = Continuando, você concorda com os <a href="%1$S" target="_blank">Termos de serviço</a> e <a href="%2$S" target="_blank">Política de privacidade</a> do Pocket
+tryitnow = Experimente-o agora
+signinfirefox = Entrar com o Firefox
+signupfirefox = Cadastre-se com o Firefox
+viewlist = Ver lista
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Salvar no Pocket
+saveToPocketCmd.label = Salvar página no Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Salvar link no Pocket
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Ver lista do Pocket
diff --git a/browser/extensions/pocket/locale/pt-PT/pocket.properties b/browser/extensions/pocket/locale/pt-PT/pocket.properties
new file mode 100644
index 000000000..90eafe77f
--- /dev/null
+++ b/browser/extensions/pocket/locale/pt-PT/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Adicionar etiquetas
+alreadyhaveacct = Já é um utilizador do Pocket?
+continueff = Continuar com o Firefox
+errorgeneric = Ocorreu um erro ao tentar guardar no Pocket.
+learnmore = Saber mais
+loginnow = Iniciar sessão
+maxtaglength = As etiquetas estão limitadas a 25 caracteres
+mustbeconnected = É necessária uma ligação à Internet para poder guardar no Pocket. Por favor, verifique a sua ligação à Internet e tente novamente.
+onlylinkssaved = Só podem ser guardadas ligações
+pagenotsaved = Página não guardada
+pageremoved = Página removida
+pagesaved = Guardado no Pocket
+processingremove = A remover página…
+processingtags = A adicionar etiquetas…
+removepage = Remover página
+save = Guardar
+saving = A guardar…
+signupemail = Registar com email
+signuptosave = Registe-se no Pocket. É gratuito.
+suggestedtags = Etiquetas sugeridas
+tagline = Guardar artigos e vídeos do Firefox para os ver no Pocket em qualquer dispositivo, em qualquer altura.
+taglinestory_one = Clique no botão Pocket para guardar qualquer artigo, vídeo ou página a partir Firefox.
+taglinestory_two = Ver no Pocket em qualquer dispositivo, a qualquer altura.
+tagssaved = Etiquetas adicionadas
+tos = Ao continuar, concorda com os <a href="%1$S" target="_blank">termos do serviço</a> e <a href="%2$S" target="_blank">política de privacidade</a> do Pocket
+tryitnow = Experimente-o agora
+signinfirefox = Iniciar sessão com Firefox
+signupfirefox = Registar com Firefox
+viewlist = Ver lista
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Guardar no Pocket
+saveToPocketCmd.label = Guardar página no Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Guardar ligação no Pocket
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Ver lista do Pocket
diff --git a/browser/extensions/pocket/locale/rm/pocket.properties b/browser/extensions/pocket/locale/rm/pocket.properties
new file mode 100644
index 000000000..803277b21
--- /dev/null
+++ b/browser/extensions/pocket/locale/rm/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Agiuntar tags
+alreadyhaveacct = Es ti gia in utilisader da Pocket?
+continueff = Cuntinuar cun Firefox
+errorgeneric = Ina errur è succedida durant empruvar da memorisar en Pocket.
+learnmore = Ulteriuras infurmaziuns
+loginnow = S'annunziar
+maxtaglength = Tags èn limitads a 25 caracters
+mustbeconnected = Ti stos esser connectà cun l'internet per pudair memorisar en Pocket. Controllescha p.pl. tia connexiun ed emprova anc ina giada.
+onlylinkssaved = Mo colliaziuns pon vegnir memorisadas
+pagenotsaved = Betg memorisà la pagina
+pageremoved = Allontanà la pagina
+pagesaved = Memorisà en Pocket
+processingremove = Allontanar la pagina…
+processingtags = Agiuntar tags…
+removepage = Allontanar la pagina
+save = Memorisar
+saving = Memorisar…
+signupemail = Sa registrar cun l'adressa dad e-mail
+signuptosave = Ta registrescha tar Pocket. Gratuit.
+suggestedtags = Tags proponids
+tagline = Memorisescha artitgels e videos ord Firefox per als vesair en Pocket, sin mintga apparat, da tut temp.
+taglinestory_one = Clicca sin il buttun da Pocket per memorisar directamain ord Firefox tge artitgel, video u pagina ch'i saja.
+taglinestory_two = Vesair en Pocket sin mintga apparat, da tut temp.
+tagssaved = Tags agiuntads
+tos = Cun cuntinuar accepteschas ti il <a href="%1$S" target="_blank">Contract da licenza</a> e las <a href="%2$S" target="_blank">Directivas per la protecziun da datas</a> da Pocket
+tryitnow = Emprova ussa
+signinfirefox = S'annunziar cun Firefox
+signupfirefox = Sa registrar cun Firefox
+viewlist = Mussar la glista
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Memorisar en Pocket
+saveToPocketCmd.label = Memorisar la pagina en Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Memorisar la colliaziun en Pocket
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Mussar la glista da Pocket
diff --git a/browser/extensions/pocket/locale/ro/pocket.properties b/browser/extensions/pocket/locale/ro/pocket.properties
new file mode 100644
index 000000000..eedb756f9
--- /dev/null
+++ b/browser/extensions/pocket/locale/ro/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Adaugă etichete
+alreadyhaveacct = Ești deja un utilizator Pocket?
+continueff = Continuă cu Firefox
+errorgeneric = A apărut o eroare la încercarea de salvare în Pocket.
+learnmore = Află mai multe
+loginnow = Autentificare
+maxtaglength = Etichetele sunt limitate la 25 de caractere
+mustbeconnected = Trebuie să fii conectat la internet pentru a salva în Pocket. Te rugăm să verifici conexiunea și să încerci din nou.
+onlylinkssaved = Doar linkurile pot fi salvate
+pagenotsaved = Pagină nesalvată
+pageremoved = Pagină eliminată
+pagesaved = Salvat în Pocket
+processingremove = Se elimină pagina…
+processingtags = Se adaugă etichete…
+removepage = Elimină pagina
+save = Salvează
+saving = Se salvează...
+signupemail = Înregistrare cu e-mail
+signuptosave = Înregistrează-te pentru Pocket. Este gratuit.
+suggestedtags = Etichete sugerate
+tagline = Salvează articole și videoclipuri din Firefox pentru a le vedea în Pocket de pe orice dispozitiv, oricând.
+taglinestory_one = Clic pe butonul Pocket pentru a salva orice articol, videoclip sau pagină din Firefox.
+taglinestory_two = Vezi în Pocket de pe orice dispozitiv, oricând.
+tagssaved = Etichete adăugate
+tos = Continuând, ești de acord cu <a href="%1$S" target="_blank">termenii de utilizare a serviciului</a> și <a href="%2$S" target="_blank">politica de confidențialitate</a> a Pocket
+tryitnow = Încearcă acum
+signinfirefox = Autentificare în Firefox
+signupfirefox = Înregistrare în Firefox
+viewlist = Vezi lista
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Salvează în Pocket
+saveToPocketCmd.label = Salvează pagina în Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Salvează linkul în Pocket
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Vezi lista Pocket
diff --git a/browser/extensions/pocket/locale/ru/pocket.properties b/browser/extensions/pocket/locale/ru/pocket.properties
new file mode 100644
index 000000000..0da716e8a
--- /dev/null
+++ b/browser/extensions/pocket/locale/ru/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Добавить теги
+alreadyhaveacct = Уже используете Pocket?
+continueff = Продолжить через Firefox
+errorgeneric = При попытке сохранить в Pocket произошла ошибка.
+learnmore = Узнайте больше
+loginnow = Войдите
+maxtaglength = Длина тега не должна превышать 25 символов
+mustbeconnected = Чтобы сохранять в Pocket, вы должны быть подключены к Интернету. Пожалуйста, проверьте ваше соединение и попробуйте снова.
+onlylinkssaved = Можно сохранять только ссылки
+pagenotsaved = Страница не сохранена
+pageremoved = Страница удалена
+pagesaved = Сохранено в Pocket
+processingremove = Удаление страницы…
+processingtags = Добавление тегов…
+removepage = Удалить страницу
+save = Сохранить
+saving = Сохранение…
+signupemail = Регистрация по эл. почте
+signuptosave = Зарегистрируйтесь в Pocket. Это бесплатно.
+suggestedtags = Рекомендуемые теги
+tagline = Сохраняйте статьи и видео из Firefox для просмотра в Pocket на любом устройстве, в любой момент.
+taglinestory_one = Щёлкните по кнопке Pocket, чтобы сохранить любую статью, видео или страницу из Firefox.
+taglinestory_two = Просматривайте их в Pocket на любом устройстве, в любой момент.
+tagssaved = Теги добавлены
+tos = Продолжая, вы принимаете <a href="%1$S" target="_blank">Условия службы</a> и <a href="%2$S" target="_blank">Политику приватности</a> Pocket
+tryitnow = Попробовать сейчас
+signinfirefox = Войти через Firefox
+signupfirefox = Регистрация через Firefox
+viewlist = Просмотреть список
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Сохранить в Pocket
+saveToPocketCmd.label = Сохранить страницу в Pocket
+saveToPocketCmd.accesskey = х
+saveLinkToPocketCmd.label = Сохранить ссылку в Pocket
+saveLinkToPocketCmd.accesskey = о
+pocketMenuitem.label = Показать список Pocket
diff --git a/browser/extensions/pocket/locale/sk/pocket.properties b/browser/extensions/pocket/locale/sk/pocket.properties
new file mode 100644
index 000000000..57327365c
--- /dev/null
+++ b/browser/extensions/pocket/locale/sk/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Pridať značky
+alreadyhaveacct = Už ste používateľom služby Pocket?
+continueff = Pokračovať s Firefoxom
+errorgeneric = Počas ukladania údajov do služby Pocket sa vyskytla chyba.
+learnmore = Ďalšie informácie
+loginnow = Prihlásiť sa
+maxtaglength = Značky môžu obsahovať najviac 25 znakov
+mustbeconnected = Ak chcete ukladať údaje do služby Pocket, musíte byť pripojený k sieti Internet. Skontrolujte svoje pripojenie a skúste to znova.
+onlylinkssaved = Uložené môžu byť len odkazy
+pagenotsaved = Stránka nebola uložená
+pageremoved = Stránka bola odstránená
+pagesaved = Uložená do služby Pocket
+processingremove = Stránka sa odstraňuje…
+processingtags = Pridávajú sa značky…
+removepage = Odstrániť stránku
+save = Uložiť
+saving = Ukladá sa…
+signupemail = Zaregistrovať sa pomocou e-mailu
+signuptosave = Zaregistrujte sa v službe Pocket. Je zadarmo.
+suggestedtags = Navrhované značky
+tagline = Ukladajte si články a videá z Firefoxu a majte ich dostupné kdekoľvek a na akomkoľvek zariadení pomocou služby Pocket.
+taglinestory_one = Kliknutím na tlačidlo Pocket vo Firefoxe uložíte akýkoľvek článok, video alebo stránku.
+taglinestory_two = Tieto sú potom so službou Pocket dostupné kdekoľvek a na akomkoľvek zariadení.
+tagssaved = Značky boli pridané
+tos = Pokračovaním vyjadrujete súhlas s <a href="%1$S" target="_blank">podmienkami používania</a> služby Pocket a so <a href="%2$S" target="_blank">zásadami ochrany osobných údajov</a>
+tryitnow = Vyskúšajte to hneď teraz
+signinfirefox = Prihlásiť sa pomocou Firefoxu
+signupfirefox = Zaregistrovať sa pomocou Firefoxu
+viewlist = Zobraziť zoznam
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Služba Pocket
+pocket-button.tooltiptext = Uložiť do služby Pocket
+saveToPocketCmd.label = Uložiť stránku do služby Pocket
+saveToPocketCmd.accesskey = P
+saveLinkToPocketCmd.label = Uložiť odkaz do služby Pocket
+saveLinkToPocketCmd.accesskey = d
+pocketMenuitem.label = Zobraziť zoznam služby Pocket
diff --git a/browser/extensions/pocket/locale/sl/pocket.properties b/browser/extensions/pocket/locale/sl/pocket.properties
new file mode 100644
index 000000000..e0451d72b
--- /dev/null
+++ b/browser/extensions/pocket/locale/sl/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Dodaj oznake
+alreadyhaveacct = Že uporabljate Pocket?
+continueff = Nadaljuj s Firefoxom
+errorgeneric = Med shranjevanjem na Pocket je prišlo do napake.
+learnmore = Več o tem
+loginnow = Prijava
+maxtaglength = Oznake so omejene na 25 znakov
+mustbeconnected = Za shranjevanje na Pocket morate biti povezani na internet. Preverite povezavo in poskusite znova.
+onlylinkssaved = Shranite lahko samo povezave
+pagenotsaved = Stran ni bila shranjena
+pageremoved = Stran odstranjena
+pagesaved = Shranjeno na Pocket
+processingremove = Odstranjevanje strani …
+processingtags = Dodajanje oznak …
+removepage = Odstrani stran
+save = Shrani
+saving = Shranjevanje …
+signupemail = Registrirajte se z e-pošto
+signuptosave = Brezplačno se registrirajte na Pocketu.
+suggestedtags = Predlagane oznake
+tagline = Shranite članke in videe v Firefoxu in si jih oglejte na Pocketu iz katere koli naprave.
+taglinestory_one = Kliknite gumb Pocket v Firefoxu in shranite članek, video ali stran.
+taglinestory_two = Oglejte si v Pocketu na kateri koli napravi.
+tagssaved = Oznake dodane
+tos = Če nadaljujete, sprejemate <a href="%1$S" target="_blank">Pogoje uporabe</a> in <a href="%2$S" target="_blank">Politiko zasebnosti</a> storitve Pocket
+tryitnow = Preizkusite ga zdaj
+signinfirefox = Prijavite se s Firefoxom
+signupfirefox = Registrirajte se s Firefoxom
+viewlist = Ogled seznama
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Shrani v Pocket
+saveToPocketCmd.label = Shrani stran v Pocket
+saveToPocketCmd.accesskey = r
+saveLinkToPocketCmd.label = Shrani povezavo v Pocket
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Pokaži seznam Pocket
diff --git a/browser/extensions/pocket/locale/sq/pocket.properties b/browser/extensions/pocket/locale/sq/pocket.properties
new file mode 100644
index 000000000..b8b17ad22
--- /dev/null
+++ b/browser/extensions/pocket/locale/sq/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Shtoni Etiketa
+alreadyhaveacct = Jeni tashmë përdorues Pocket-i?
+continueff = Vazhdoni me Firefox-in
+errorgeneric = Pati një gabim teksa përpiqej të ruante te Pocket.
+learnmore = Mësoni më tepër
+loginnow = Hyni
+maxtaglength = Etiketat kufizohen deri në 25 shenja
+mustbeconnected = Që të ruani në Pocket, duhet të jeni i lidhur në Internet. Ju lutemi, kontrolloni lidhjen tuaj dhe riprovoni.
+onlylinkssaved = Mund të ruhen vetëm lidhje
+pagenotsaved = Faqja S’u Ruajt
+pageremoved = Faqja u Hoq
+pagesaved = U ruajt te Pocket
+processingremove = Po hiqet Faqja…
+processingtags = Po shtohen etiketa…
+removepage = Hiqe Faqen
+save = Ruaje
+saving = Po ruhet…
+signupemail = Regjistrohuni me email
+signuptosave = Regjistrohuni në Pocket. Është falas.
+suggestedtags = Etiketa të Këshilluara
+tagline = Ruani që nga Firefoxc-i artikuj dhe video për t’i parë në Pocket në çfarëdo pajisje, kurdo.
+taglinestory_one = Klikoni butonin Pocket që të ruani që nga Firefox-i çfarëdo artikulli, video ose faqe.
+taglinestory_two = Shihini në Pocket, në çfarëdo pajisje, kurdo.
+tagssaved = Etiketat u Shtuan
+tos = Duke vazhduar, pajtoheni me <a href="%1$S" target="_blank">Kushtet e Shërbimit</a> dhe <a href="%2$S" target="_blank">Rregullat e Privatësisë</a> për Pocket-in
+tryitnow = Provojeni Që Tani
+signinfirefox = Hyni me Firefox
+signupfirefox = Regjistrohuni me Firefox
+viewlist = Shihni Listën
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Ruajeni te Pocket
+saveToPocketCmd.label = Ruajeni Faqen te Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Ruajeni lidhjen te Pocket
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Shihni Listën te Pocket
diff --git a/browser/extensions/pocket/locale/sr/pocket.properties b/browser/extensions/pocket/locale/sr/pocket.properties
new file mode 100644
index 000000000..c3dbf2ece
--- /dev/null
+++ b/browser/extensions/pocket/locale/sr/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Додај ознаку
+alreadyhaveacct = Већ сте Pocket корисник?
+continueff = Настави са Firefox-ом
+errorgeneric = Десила се грешка при покушају снимања у Pocket.
+learnmore = Сазнајте више
+loginnow = Пријава
+maxtaglength = Ознаке су ограничене на 25 карактера
+mustbeconnected = Морате бити повезани на интернет да бисте снимили у Pocket. Проверити везу и покушајте поново.
+onlylinkssaved = Само се везе могу снимити
+pagenotsaved = Страница није снимљена
+pageremoved = Страница уклоњена
+pagesaved = Снимљено у Pocket
+processingremove = Уклањам страницу…
+processingtags = Додајем ознаку…
+removepage = Уклони страницу
+save = Сними
+saving = Снимам…
+signupemail = Региструј се са е-поштом
+signuptosave = Региструјте се да користите Pocket. Бесплатно је.
+suggestedtags = Предложене ознаке
+tagline = Снимите чланке и видео снимке из Firefox-а да бисте их погледали у Pocket-у на било ком уређају било када.
+taglinestory_one = Кликните на Pocket дугме да бисте снимили чланак, видео или страницу из Firefox-а.
+taglinestory_two = Погледајте садржај у Pocket-у на било ком уређају било када.
+tagssaved = Ознаке додате
+tos = Настављањем прихватате <a href="%1$S" target="_blank">услове коришћења</a> и <a href="%2$S" target="_blank">полису приватности</a> Pocket-а
+tryitnow = Покушајте сада
+signinfirefox = Пријави се
+signupfirefox = Региструј се
+viewlist = Прикажи листу
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Сними у Pocket
+saveToPocketCmd.label = Сними страницу у Pocket
+saveToPocketCmd.accesskey = С
+saveLinkToPocketCmd.label = Сними везу у Pocket
+saveLinkToPocketCmd.accesskey = в
+pocketMenuitem.label = Прикажи Pocket листу
diff --git a/browser/extensions/pocket/locale/sv-SE/pocket.properties b/browser/extensions/pocket/locale/sv-SE/pocket.properties
new file mode 100644
index 000000000..e01ac7373
--- /dev/null
+++ b/browser/extensions/pocket/locale/sv-SE/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Lägg till etiketter
+alreadyhaveacct = Redan en Pocket användare?
+continueff = Fortsätt med Firefox\u0020
+errorgeneric = Ett fel upptäcktes då du försökte spara till Pocket.
+learnmore = Läs mer
+loginnow = Logga in
+maxtaglength = Etiketter kan max vara 25 tecken
+mustbeconnected = Du måste vara ansluten till internet för att kunna spara till Pocket. Kontrollera din anslutning och försök igen.
+onlylinkssaved = Bara länkar kan sparas\u0020
+pagenotsaved = Sidan sparades inte\u0020
+pageremoved = Sidan borttagen
+pagesaved = Spara till Pocket\u0020
+processingremove = Tar bort sida…
+processingtags = Lägger till etiketter…
+removepage = Ta bort sida
+save = Spara
+saving = Sparar…
+signupemail = Registrera dig med din E-postadress
+signuptosave = Registrera dig för Pocket. Det är gratis.
+suggestedtags = Föreslagna etiketter
+tagline = Spara artiklar och videor från Firefox för att visa i Pocket på vilken enhet som helst, när som helst.
+taglinestory_one = Klicka på Pocket knappen för att spara vilken artikel, video eller sida som helst från Firefox.\u0020
+taglinestory_two = Visa i Pocket på vilken enhet som helst, när som helst.\u0020
+tagssaved = Etiketter Tillagda
+tos = Genom att fortsätta godkänner du Pocket's <a href="%1$S" target="_blank">användarvillkor</a> och <a href="%2$S" target="_blank">sekretesspolicy</a>
+tryitnow = Prova nu
+signinfirefox = Logga in med Firefox\u0020
+signupfirefox = Registrera dig med Firefox\u0020
+viewlist = Visa lista
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Spara till Pocket
+saveToPocketCmd.label = Spara sida till Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Spara Länk till Pocket
+saveLinkToPocketCmd.accesskey = l
+pocketMenuitem.label = Visa Pocket Lista\u0020
diff --git a/browser/extensions/pocket/locale/te/pocket.properties b/browser/extensions/pocket/locale/te/pocket.properties
new file mode 100644
index 000000000..2e9552793
--- /dev/null
+++ b/browser/extensions/pocket/locale/te/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = టాగ్‌లను జోడించు
+alreadyhaveacct = ఇప్పటికే ఒక పాకెట్ యూజర్?
+continueff = ఫైర్ఫాక్స్ తో కొనసాగించుము
+errorgeneric = పాకెట్ కు సేవ్ చేయడానికి ప్రయత్నిస్తున్నప్పుడు లోపం ఉంది.
+learnmore = మరింత తెలుసుకోండి
+loginnow = లాగ్ ఇన్
+maxtaglength = టాగ్లు 25 అక్షరాలకు పరిమితం చేయబడ్డాయి
+mustbeconnected = మీరు పాకెట్ కు సేవ్ చేయడానికి ఇంటర్నెట్ కనెక్ట్ చేయక తప్పదు. మీ కనెక్షన్ను తనిఖీ చేసి, మళ్ళీ ప్రయత్నించండి.
+onlylinkssaved = కేవలం లింకులు సేవ్ చేయవచ్చు
+pagenotsaved = పేజీ సేవ్ చేయబడలేదు
+pageremoved = పేజీ తీసివేయబడెను
+pagesaved = పాకెట్ కు సేవ్ చేయబడింది
+processingremove = పేజీని తొలగించు…
+processingtags = టాగ్లు జోడిస్తోంది...
+removepage = పేజీని తొలగించు
+save = సేవ్ చేయి
+saving = సేవ్ చేస్తోంది...
+signupemail = ఇమెయిల్ తో సైన్అప్ అవ్వండ్
+signuptosave = పాకెట్ కోసం సైన్ అప్ చేయండి. ఇది ఉచితం.
+suggestedtags = సూచించిన టాగ్లు
+tagline = ఏ పరికరం, ఏ సమయం లో పాకెట్ వీక్షించడానికి Firefox నుండి వ్యాసాలు మరియు వీడియోలను సేవ్ చేయవచ్చు.
+taglinestory_one = ఫైర్ఫాక్సు నుండి ఒక వ్యాసం, వీడియో లేదా పేజీ సేవ్ పాకెట్ బటన్ క్లిక్ చేయండి.
+taglinestory_two = ఏ పరికరంలో అయినా, ఏ సమయంలో అయినా పాకెట్ లో చూడండి.
+tagssaved = టాగ్లు చేర్చబడింది
+tos = కొనసాగించడం ద్వారా, మీరు పాకెట్ యొక్క <a href="%1$S" target="_blank"> సేవా నిబంధనలు</a> మరియు <a href="%2$S" target="_blank"> గోప్యతా విధానము</a> ను అంగీకరిచబడుతారు
+tryitnow = దీన్ని ఇప్పుడు ప్రయత్నించండి
+signinfirefox = ఫైర్ఫాక్సుకు ప్రవేశించండి
+signupfirefox = ఫైర్ఫాక్సుకు ప్రవేశించండి
+viewlist = జాబితాను చూడండి
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = పాకెట్
+pocket-button.tooltiptext = పాకెట్ కు సేవ్ చేయండి
+saveToPocketCmd.label = పాకెట్ కు సేవ్ చేయండి
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = పాకెట్ కు లింక్ ను సేవ్ చేయండి
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = పాకెట్ జాబితా చూడండి
diff --git a/browser/extensions/pocket/locale/th/pocket.properties b/browser/extensions/pocket/locale/th/pocket.properties
new file mode 100644
index 000000000..6cdf1c9ec
--- /dev/null
+++ b/browser/extensions/pocket/locale/th/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = เพิ่มป้ายกำกับ
+alreadyhaveacct = เป็นผู้ใช้ Pocket อยู่แล้ว?
+continueff = ดำเนินการต่อด้วย Firefox
+errorgeneric = เกิดข้อผิดพลาดระหว่างการบันทึกไปยัง Pocket
+learnmore = เรียนรู้เพิ่มเติม
+loginnow = เข้าสู่ระบบ
+maxtaglength = ป้ายกำกับถูกจำกัดไว้ที่ 25 ตัวอักษร
+mustbeconnected = คุณต้องเชื่อมต่อกับอินเทอร์เน็ตก่อนที่จะบันทึก Pocket โปรดตรวจสอบการเชื่อมต่อของคุณและลองอีกครั้ง
+onlylinkssaved = ลิงก์เท่านั้นที่สามารถถูกบันทึกได้
+pagenotsaved = หน้าไม่ถูกบันทึก
+pageremoved = ลบหน้าแล้ว
+pagesaved = บันทึกไปยัง Pocket
+processingremove = กำลังลบหน้า…
+processingtags = กำลังเพิ่มป้ายกำกับ…
+removepage = ลบหน้า
+save = บันทึก
+saving = กำลังบันทึก…
+signupemail = ลงทะเบียนด้วยอีเมล
+signuptosave = ไม่มีค่าใช้จ่ายในการลงทะเบียน Pocket
+suggestedtags = ป้ายกำกับที่ถูกแนะนำ
+tagline = บันทึกบทความและวิดีโอจาก Firefox เพื่อดูใน Pocket บนอุปกรณ์ต่าง ๆ เวลาไหนก็ได้
+taglinestory_one = คลิกปุ่ม Pocket เพื่อบันทึกบทความ วิดีโอ หรือหน้าจาก Firefox
+taglinestory_two = ดูใน Pocket บนอุปกรณ์ต่าง ๆ เวลาไหนก็ได้
+tagssaved = ป้ายกำกับถูกเพิ่มแล้ว
+tos = หากตกลง หมายความว่า คุณยอมรับ<a href="%1$S" target="_blank">เงื่อนไขการให้บริการ</a> และ<a href="%2$S" target="_blank">นโยบายความเป็นส่วนตัว</a>ของ Pocket
+tryitnow = ลองเลย
+signinfirefox = ลงชื่อเข้าด้วย Firefox
+signupfirefox = ลงทะเบียนกับ Firefox
+viewlist = ดูรายการ
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = บันทึกไปยัง Pocket
+saveToPocketCmd.label = บันทึกหน้าไปยัง Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = บันทึกลิงก์ไปยัง Pocket
+saveLinkToPocketCmd.accesskey = ป
+pocketMenuitem.label = ดูรายการ Pocket
diff --git a/browser/extensions/pocket/locale/tr/pocket.properties b/browser/extensions/pocket/locale/tr/pocket.properties
new file mode 100644
index 000000000..ea1970a7d
--- /dev/null
+++ b/browser/extensions/pocket/locale/tr/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Etiket ekle
+alreadyhaveacct = Zaten Pocket kullanıcısı mısınız?
+continueff = Firefox ile devam et
+errorgeneric = Pocket’a kaydetmeye çalışırken bir hata oluştu.
+learnmore = Daha fazla bilgi al
+loginnow = Giriş yapın
+maxtaglength = Etiketler en fazla 25 karakter olabilir
+mustbeconnected = Pocket’a kaydetmek için internete bağlı olmalısınız. Lütfen bağlantınızı kontrol edip yeniden deneyin.
+onlylinkssaved = Yalnızca bağlantılar kaydedilebilir
+pagenotsaved = Sayfa kaydedilmedi
+pageremoved = Sayfa silindi
+pagesaved = Pocket’a kaydedildi
+processingremove = Sayfa siliniyor…
+processingtags = Etiketler ekleniyor…
+removepage = Sayfayı sil
+save = Kaydet
+saving = Kaydediliyor…
+signupemail = E-postayla kaydol
+signuptosave = Pocket’a kaydolun. Ücretsiz!
+suggestedtags = Önerilen etiketler
+tagline = İstediğiniz cihazda, istediğiniz zaman görmek istediğiniz yazı ve videoları Firefox’tan Pocket’a kaydedin.
+taglinestory_one = Firefox’ta istediğiniz yazıyı, videoyu veya sayfayı kaydetmek için Pocket düğmesine tıklayın.
+taglinestory_two = İstediğiniz cihazda, istediğiniz zaman Pocket’tan bakın.
+tagssaved = Etiketler eklendi
+tos = Devam ederseniz Pocket'ın <a href="%1$S" target="_blank">Kullanım Koşullarını</a> ve <a href="%2$S" target="_blank">Gizlilik İlkelerini</a> kabul etmiş sayılırsınız
+tryitnow = Hemen deneyin
+signinfirefox = Firefox ile giriş yap
+signupfirefox = Firefox ile kaydol
+viewlist = Listeyi göster
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Pocket’a kaydet
+saveToPocketCmd.label = Sayfayı Pocket’a kaydet
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = Bağlantıyı Pocket’a kaydet
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = Pocket listesini göster
diff --git a/browser/extensions/pocket/locale/uk/pocket.properties b/browser/extensions/pocket/locale/uk/pocket.properties
new file mode 100644
index 000000000..d15049b2c
--- /dev/null
+++ b/browser/extensions/pocket/locale/uk/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = Додати мітки
+alreadyhaveacct = Вже використовуєте Pocket?
+continueff = Продовжити з Firefox
+errorgeneric = При спробі збереження в Pocket сталася помилка.
+learnmore = Докладніше
+loginnow = Увійти
+maxtaglength = Мітки мають обмеження до 25 символів
+mustbeconnected = Для можливості збереження в Pocket ви повинні бути підключені до Інтернету. Перевірте своє з'єднання і спробуйте знову.
+onlylinkssaved = Можна зберігати лише посилання
+pagenotsaved = Сторінку не збережено
+pageremoved = Сторінку вилучено
+pagesaved = Збережено в Pocket
+processingremove = Вилучення сторінки…
+processingtags = Додавання міток…
+removepage = Вилучити сторінку
+save = Зберегти
+saving = Збереження…
+signupemail = Реєстрація за адресою електронної пошти
+signuptosave = Зареєструйтеся в Pocket. Це безплатно.
+suggestedtags = Пропоновані мітки
+tagline = Зберігайте статті та відео з Firefox, щоб переглядати їх в Pocket на будь-якому пристрої та в будь-який час.
+taglinestory_one = Натисніть кнопку Pocket для збереження будь-якої статті, відео чи сторінки з Firefox.
+taglinestory_two = Переглядайте в Pocket на будь-якому пристрої та в будь-який час.
+tagssaved = Мітки додано
+tos = Продовжуючи, ви погоджуєтесь з <a href="%1$S" target="_blank">Умовами використання</a> і <a href="%2$S" target="_blank">Політикою приватності</a>
+tryitnow = Спробувати зараз
+signinfirefox = Увійти через Firefox
+signupfirefox = Реєстрація через Firefox
+viewlist = Перегляд списку
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = Зберегти в Pocket
+saveToPocketCmd.label = Зберегти сторінку в Pocket
+saveToPocketCmd.accesskey = З
+saveLinkToPocketCmd.label = Зберегти посилання в Pocket
+saveLinkToPocketCmd.accesskey = п
+pocketMenuitem.label = Перегляд списку Pocket
diff --git a/browser/extensions/pocket/locale/zh-CN/pocket.properties b/browser/extensions/pocket/locale/zh-CN/pocket.properties
new file mode 100644
index 000000000..e913887b8
--- /dev/null
+++ b/browser/extensions/pocket/locale/zh-CN/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = 添加标签
+alreadyhaveacct = 已有 Pocket 账号?
+continueff = 使用 Firefox 继续
+errorgeneric = 尝试保存到 Pocket 时出错。
+learnmore = 详细了解
+loginnow = 登录
+maxtaglength = 标签不能超过 25 个字符
+mustbeconnected = 您必须已连接互联网才能保存到 Pocket。请检查您的连接,然后再试。
+onlylinkssaved = 只有链接能被保存
+pagenotsaved = 页面未保存
+pageremoved = 页面已移除
+pagesaved = 已保存到 Pocket
+processingremove = 正在移除页面…
+processingtags = 正在添加标签…
+removepage = 移除页面
+save = 保存
+saving = 正在保存…
+signupemail = 通过电子邮件注册
+signuptosave = 免费注册 Pocket。
+suggestedtags = 推荐标签
+tagline = 在 Firefox 上保存文章和视频,以供在任何时间、任何设备上用 Pocket 访问。
+taglinestory_one = 点击 Pocket 按钮保存 Firefox 上的任何文章、视频或页面。
+taglinestory_two = 在任何时间、任何设备上的 Pocket 中查看。
+tagssaved = 标签已添加
+tos = 继续则表示您同意 Pocket 的<a href="%1$S" target="_blank">服务条款</a>和<a href="%2$S" target="_blank">隐私政策</a>
+tryitnow = 立即尝试
+signinfirefox = 使用 Firefox 登录
+signupfirefox = 使用 Firefox 注册
+viewlist = 查看列表
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = 保存到 Pocket
+saveToPocketCmd.label = 保存页面到 Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = 保存链接到 Pocket
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = 查看 Pocket 列表
diff --git a/browser/extensions/pocket/locale/zh-TW/pocket.properties b/browser/extensions/pocket/locale/zh-TW/pocket.properties
new file mode 100644
index 000000000..02cf5223b
--- /dev/null
+++ b/browser/extensions/pocket/locale/zh-TW/pocket.properties
@@ -0,0 +1,43 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+addtags = 新增標籤
+alreadyhaveacct = 已經是 Pocket 使用者了嗎?
+continueff = 使用 Firefox 繼續
+errorgeneric = 嘗試儲存至 Pocket 時發生錯誤。
+learnmore = 更多資訊
+loginnow = 登入
+maxtaglength = 標籤僅能有 25 字元
+mustbeconnected = 您必須連線至網際網路才能儲存至 Pocket。請檢查您的連線狀態後再試一次。
+onlylinkssaved = 僅能儲存鏈結
+pagenotsaved = 未儲存頁面
+pageremoved = 已移除頁面
+pagesaved = 已儲存至 Pocket
+processingremove = 正在移除頁面…
+processingtags = 正在新增標籤…
+removepage = 移除頁面
+save = 儲存
+saving = 儲存中…
+signupemail = 使用電子郵件地址註冊
+signuptosave = 免費註冊 Pocket 帳號。
+suggestedtags = 建議的標籤
+tagline = 隨時隨地在任何裝置上的 Firefox 來儲存文章與影片,稍後再用 Pocket 開啟。
+taglinestory_one = 在 Firefox 中點擊 Pocket 按鈕來儲存任何文章、影片或網頁。
+taglinestory_two = 隨時隨地在任何裝置上用 Pocket 檢視。
+tagssaved = 已新增標籤
+tos = 繼續使用就代表您同意 Pocket 的 <a href="%1$S" target="_blank">服務條款</a> 及 <a href="%2$S" target="_blank">隱私權保護政策</a>
+tryitnow = 立刻試試
+signinfirefox = 使用 Firefox 登入
+signupfirefox = 使用 Firefox 註冊
+viewlist = 檢視清單
+
+# LOCALIZATION NOTE(pocket-button.label, pocket-button.tooltiptext, saveToPocketCmd.label, saveLinkToPocketCmd.label, pocketMenuitem.label):
+# "Pocket" is a brand name.
+pocket-button.label = Pocket
+pocket-button.tooltiptext = 儲存至 Pocket
+saveToPocketCmd.label = 將頁面儲存至 Pocket
+saveToPocketCmd.accesskey = k
+saveLinkToPocketCmd.label = 將鏈結儲存至 Pocket
+saveLinkToPocketCmd.accesskey = o
+pocketMenuitem.label = 檢視 Pocket 清單
diff --git a/browser/extensions/pocket/moz.build b/browser/extensions/pocket/moz.build
new file mode 100644
index 000000000..495e48a62
--- /dev/null
+++ b/browser/extensions/pocket/moz.build
@@ -0,0 +1,22 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+DEFINES['MOZ_APP_VERSION'] = CONFIG['MOZ_APP_VERSION']
+DEFINES['MOZ_APP_MAXVERSION'] = CONFIG['MOZ_APP_MAXVERSION']
+
+DIRS += ['locale']
+
+FINAL_TARGET_FILES.features['firefox@getpocket.com'] += [
+ 'bootstrap.js'
+]
+
+FINAL_TARGET_PP_FILES.features['firefox@getpocket.com'] += [
+ 'install.rdf.in'
+]
+
+BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
+
+JAR_MANIFESTS += ['jar.mn']
diff --git a/browser/extensions/pocket/skin/linux/Toolbar-inverted.png b/browser/extensions/pocket/skin/linux/Toolbar-inverted.png
new file mode 100644
index 000000000..68f5125ea
--- /dev/null
+++ b/browser/extensions/pocket/skin/linux/Toolbar-inverted.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/linux/Toolbar-inverted@2x.png b/browser/extensions/pocket/skin/linux/Toolbar-inverted@2x.png
new file mode 100644
index 000000000..89056295c
--- /dev/null
+++ b/browser/extensions/pocket/skin/linux/Toolbar-inverted@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/linux/Toolbar.png b/browser/extensions/pocket/skin/linux/Toolbar.png
new file mode 100644
index 000000000..be9b0e6d2
--- /dev/null
+++ b/browser/extensions/pocket/skin/linux/Toolbar.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/linux/Toolbar@2x.png b/browser/extensions/pocket/skin/linux/Toolbar@2x.png
new file mode 100644
index 000000000..5dc4e754a
--- /dev/null
+++ b/browser/extensions/pocket/skin/linux/Toolbar@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/linux/menuPanel.png b/browser/extensions/pocket/skin/linux/menuPanel.png
new file mode 100644
index 000000000..55bc46cc9
--- /dev/null
+++ b/browser/extensions/pocket/skin/linux/menuPanel.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/linux/menuPanel@2x.png b/browser/extensions/pocket/skin/linux/menuPanel@2x.png
new file mode 100644
index 000000000..ad13ca4ce
--- /dev/null
+++ b/browser/extensions/pocket/skin/linux/menuPanel@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/linux/pocket.css b/browser/extensions/pocket/skin/linux/pocket.css
new file mode 100644
index 000000000..156964923
--- /dev/null
+++ b/browser/extensions/pocket/skin/linux/pocket.css
@@ -0,0 +1,10 @@
+@import url("chrome://pocket-shared/skin/pocket.css");
+
+#nav-bar #pocket-button > .toolbarbutton-icon {
+ padding: 2px 6px;
+}
+
+:-moz-any(#TabsToolbar, .widget-overflow-list) #pocket-button > .toolbarbutton-icon {
+ max-width: 18px;
+ padding: 0;
+} \ No newline at end of file
diff --git a/browser/extensions/pocket/skin/osx/Toolbar-inverted.png b/browser/extensions/pocket/skin/osx/Toolbar-inverted.png
new file mode 100644
index 000000000..0f4d57b4e
--- /dev/null
+++ b/browser/extensions/pocket/skin/osx/Toolbar-inverted.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/osx/Toolbar-inverted@2x.png b/browser/extensions/pocket/skin/osx/Toolbar-inverted@2x.png
new file mode 100644
index 000000000..03c3b42d5
--- /dev/null
+++ b/browser/extensions/pocket/skin/osx/Toolbar-inverted@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/osx/Toolbar-yosemite.png b/browser/extensions/pocket/skin/osx/Toolbar-yosemite.png
new file mode 100644
index 000000000..28602b186
--- /dev/null
+++ b/browser/extensions/pocket/skin/osx/Toolbar-yosemite.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/osx/Toolbar-yosemite@2x.png b/browser/extensions/pocket/skin/osx/Toolbar-yosemite@2x.png
new file mode 100644
index 000000000..53040cb46
--- /dev/null
+++ b/browser/extensions/pocket/skin/osx/Toolbar-yosemite@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/osx/Toolbar.png b/browser/extensions/pocket/skin/osx/Toolbar.png
new file mode 100644
index 000000000..1a8d7a51c
--- /dev/null
+++ b/browser/extensions/pocket/skin/osx/Toolbar.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/osx/Toolbar@2x.png b/browser/extensions/pocket/skin/osx/Toolbar@2x.png
new file mode 100644
index 000000000..91bf3ef6f
--- /dev/null
+++ b/browser/extensions/pocket/skin/osx/Toolbar@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/osx/menuPanel-yosemite.png b/browser/extensions/pocket/skin/osx/menuPanel-yosemite.png
new file mode 100644
index 000000000..30b475cc0
--- /dev/null
+++ b/browser/extensions/pocket/skin/osx/menuPanel-yosemite.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/osx/menuPanel-yosemite@2x.png b/browser/extensions/pocket/skin/osx/menuPanel-yosemite@2x.png
new file mode 100644
index 000000000..389d96ec7
--- /dev/null
+++ b/browser/extensions/pocket/skin/osx/menuPanel-yosemite@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/osx/menuPanel.png b/browser/extensions/pocket/skin/osx/menuPanel.png
new file mode 100644
index 000000000..d2bf61888
--- /dev/null
+++ b/browser/extensions/pocket/skin/osx/menuPanel.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/osx/menuPanel@2x.png b/browser/extensions/pocket/skin/osx/menuPanel@2x.png
new file mode 100644
index 000000000..f58afbc4d
--- /dev/null
+++ b/browser/extensions/pocket/skin/osx/menuPanel@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/osx/pocket.css b/browser/extensions/pocket/skin/osx/pocket.css
new file mode 100644
index 000000000..534a881a5
--- /dev/null
+++ b/browser/extensions/pocket/skin/osx/pocket.css
@@ -0,0 +1,42 @@
+@import url("chrome://pocket-shared/skin/pocket.css");
+
+#pocket-button[cui-areatype="toolbar"] > .toolbarbutton-icon {
+ max-width: 18px;
+ margin: 0;
+}
+
+#pocket-button[cui-areatype="toolbar"][open] {
+ -moz-image-region: rect(36px, 18px, 54px, 0);
+}
+
+@media (min-resolution: 2dppx) {
+ #panelMenu_pocket,
+ #menu_pocket,
+ #BMB_pocket {
+ list-style-image: url("chrome://pocket/content/panels/img/pocketmenuitem16@2x.png");
+ }
+
+ #panelMenu_pocket > .toolbarbutton-icon {
+ width: 16px;
+ }
+}
+
+@media not all and (min-resolution: 1.1dppx) {
+ #pocket-button:hover:active:not([disabled="true"]):not([cui-areatype="menu-panel"]) {
+ -moz-image-region: rect(18px, 18px, 36px, 0);
+ }
+}
+
+@media (min-resolution: 1.1dppx) {
+ #pocket-button[cui-areatype="toolbar"][open] {
+ -moz-image-region: rect(72px, 36px, 108px, 0);
+ }
+
+ #pocket-button:hover:active:not([disabled="true"]):not([cui-areatype="menu-panel"]) {
+ -moz-image-region: rect(36px, 36px, 72px, 0);
+ }
+}
+
+#PanelUI-pocketView[mainview=true] > .panel-subview-body > #pocket-panel-iframe {
+ border-radius: var(--arrowpanel-border-radius);
+}
diff --git a/browser/extensions/pocket/skin/shared/pocket.css b/browser/extensions/pocket/skin/shared/pocket.css
new file mode 100644
index 000000000..ec46e1890
--- /dev/null
+++ b/browser/extensions/pocket/skin/shared/pocket.css
@@ -0,0 +1,79 @@
+/* Bug 1164419 - increase Pocket panel size to accomidate wider Russian text. */
+panelmultiview[mainViewId=PanelUI-pocketView] > .panel-viewcontainer > .panel-viewstack > .panel-mainview:not([panelid="PanelUI-popup"]) {
+ max-width: 33em; /* standaloneSubviewWidth + 3 */
+}
+
+.cui-widget-panel[viewId="PanelUI-pocketView"] > .panel-arrowcontainer > .panel-arrowcontent {
+ padding-top: 0;
+ padding-bottom: 0;
+}
+
+#PanelUI-pocketView > .panel-subview-body,
+#PanelUI-pocketView {
+ overflow: visible;
+}
+
+#pocket-button {
+ list-style-image: url("chrome://pocket/skin/Toolbar.png");
+ -moz-image-region: rect(0, 18px, 18px, 0);
+}
+
+toolbar[brighttext] #pocket-button {
+ list-style-image: url(chrome://pocket/skin/Toolbar-inverted.png);
+}
+
+@media not all and (min-resolution: 1.1dppx) {
+ #pocket-button[cui-areatype="menu-panel"],
+ toolbarpaletteitem[place="palette"] > #pocket-button {
+ list-style-image: url(chrome://pocket/skin/menuPanel.png);
+ -moz-image-region: rect(0, 32px, 32px, 0);
+ }
+
+ #pocket-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
+ -moz-image-region: rect(32px, 32px, 64px, 0);
+ }
+}
+
+@media (min-resolution: 1.1dppx) {
+ #pocket-button[cui-areatype="menu-panel"],
+ toolbarpaletteitem[place="palette"] > #pocket-button {
+ list-style-image: url(chrome://pocket/skin/menuPanel@2x.png);
+ -moz-image-region: rect(0px, 64px, 64px, 0);
+ }
+
+ #pocket-button[cui-areatype="menu-panel"][panel-multiview-anchor=true] {
+ -moz-image-region: rect(64px, 64px, 128px, 0);
+ }
+}
+
+#pocket-button[cui-areatype="toolbar"] {
+ -moz-image-region: rect(0, 18px, 18px, 0);
+}
+
+#pocket-button[cui-areatype="toolbar"][open] {
+ -moz-image-region: rect(18px, 18px, 36px, 0);
+}
+
+@media (min-resolution: 1.1dppx) {
+ #pocket-button {
+ list-style-image: url("chrome://pocket/skin/Toolbar@2x.png");
+ }
+
+ toolbar[brighttext] #pocket-button {
+ list-style-image: url("chrome://pocket/skin/Toolbar-inverted@2x.png");
+ }
+
+ #pocket-button[cui-areatype="toolbar"] {
+ -moz-image-region: rect(0, 36px, 36px, 0px);
+ }
+
+ #pocket-button[cui-areatype="toolbar"][open] {
+ -moz-image-region: rect(36px, 36px, 72px, 0px);
+ }
+}
+
+#panelMenu_pocket,
+#menu_pocket,
+#BMB_pocket {
+ list-style-image: url("chrome://pocket/content/panels/img/pocketmenuitem16.png");
+}
diff --git a/browser/extensions/pocket/skin/windows/Toolbar-XP.png b/browser/extensions/pocket/skin/windows/Toolbar-XP.png
new file mode 100644
index 000000000..9220a207f
--- /dev/null
+++ b/browser/extensions/pocket/skin/windows/Toolbar-XP.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/windows/Toolbar-aero.png b/browser/extensions/pocket/skin/windows/Toolbar-aero.png
new file mode 100644
index 000000000..7b373acb9
--- /dev/null
+++ b/browser/extensions/pocket/skin/windows/Toolbar-aero.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/windows/Toolbar-aero@2x.png b/browser/extensions/pocket/skin/windows/Toolbar-aero@2x.png
new file mode 100644
index 000000000..6e83dcc60
--- /dev/null
+++ b/browser/extensions/pocket/skin/windows/Toolbar-aero@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/windows/Toolbar-inverted.png b/browser/extensions/pocket/skin/windows/Toolbar-inverted.png
new file mode 100644
index 000000000..70e95f464
--- /dev/null
+++ b/browser/extensions/pocket/skin/windows/Toolbar-inverted.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/windows/Toolbar-inverted@2x.png b/browser/extensions/pocket/skin/windows/Toolbar-inverted@2x.png
new file mode 100644
index 000000000..ba0b7e2af
--- /dev/null
+++ b/browser/extensions/pocket/skin/windows/Toolbar-inverted@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/windows/Toolbar-lunaSilver.png b/browser/extensions/pocket/skin/windows/Toolbar-lunaSilver.png
new file mode 100644
index 000000000..5afe7ca44
--- /dev/null
+++ b/browser/extensions/pocket/skin/windows/Toolbar-lunaSilver.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/windows/Toolbar-win8.png b/browser/extensions/pocket/skin/windows/Toolbar-win8.png
new file mode 100644
index 000000000..208dc03ae
--- /dev/null
+++ b/browser/extensions/pocket/skin/windows/Toolbar-win8.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/windows/Toolbar-win8@2x.png b/browser/extensions/pocket/skin/windows/Toolbar-win8@2x.png
new file mode 100644
index 000000000..3704f0885
--- /dev/null
+++ b/browser/extensions/pocket/skin/windows/Toolbar-win8@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/windows/Toolbar.png b/browser/extensions/pocket/skin/windows/Toolbar.png
new file mode 100644
index 000000000..4801961f8
--- /dev/null
+++ b/browser/extensions/pocket/skin/windows/Toolbar.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/windows/Toolbar@2x.png b/browser/extensions/pocket/skin/windows/Toolbar@2x.png
new file mode 100644
index 000000000..f3a1cc738
--- /dev/null
+++ b/browser/extensions/pocket/skin/windows/Toolbar@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/windows/menuPanel-aero.png b/browser/extensions/pocket/skin/windows/menuPanel-aero.png
new file mode 100644
index 000000000..459e82634
--- /dev/null
+++ b/browser/extensions/pocket/skin/windows/menuPanel-aero.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/windows/menuPanel-aero@2x.png b/browser/extensions/pocket/skin/windows/menuPanel-aero@2x.png
new file mode 100644
index 000000000..eef525741
--- /dev/null
+++ b/browser/extensions/pocket/skin/windows/menuPanel-aero@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/windows/menuPanel.png b/browser/extensions/pocket/skin/windows/menuPanel.png
new file mode 100644
index 000000000..55bc46cc9
--- /dev/null
+++ b/browser/extensions/pocket/skin/windows/menuPanel.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/windows/menuPanel@2x.png b/browser/extensions/pocket/skin/windows/menuPanel@2x.png
new file mode 100644
index 000000000..ad13ca4ce
--- /dev/null
+++ b/browser/extensions/pocket/skin/windows/menuPanel@2x.png
Binary files differ
diff --git a/browser/extensions/pocket/skin/windows/pocket.css b/browser/extensions/pocket/skin/windows/pocket.css
new file mode 100644
index 000000000..011b821a9
--- /dev/null
+++ b/browser/extensions/pocket/skin/windows/pocket.css
@@ -0,0 +1,16 @@
+@import url("chrome://pocket-shared/skin/pocket.css");
+
+#nav-bar #pocket-button > .toolbarbutton-icon {
+ padding: calc(var(--toolbarbutton-vertical-inner-padding)) 6px;
+}
+
+:-moz-any(#TabsToolbar, .widget-overflow-list) #pocket-button > .toolbarbutton-icon {
+ max-width: 18px;
+ padding: 0;
+}
+
+@media (-moz-windows-theme: luna-silver) and (max-resolution: 1dppx) {
+ #pocket-button {
+ list-style-image: url(Toolbar-lunaSilver.png);
+ }
+}
diff --git a/browser/extensions/pocket/test/.eslintrc.js b/browser/extensions/pocket/test/.eslintrc.js
new file mode 100644
index 000000000..c764b133d
--- /dev/null
+++ b/browser/extensions/pocket/test/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+ "extends": [
+ "../../../../testing/mochitest/browser.eslintrc.js"
+ ]
+};
diff --git a/browser/extensions/pocket/test/browser.ini b/browser/extensions/pocket/test/browser.ini
new file mode 100644
index 000000000..3e0be8736
--- /dev/null
+++ b/browser/extensions/pocket/test/browser.ini
@@ -0,0 +1,6 @@
+[DEFAULT]
+support-files =
+ head.js
+ test.html
+
+[browser_pocket_ui_check.js]
diff --git a/browser/extensions/pocket/test/browser_pocket_ui_check.js b/browser/extensions/pocket/test/browser_pocket_ui_check.js
new file mode 100644
index 000000000..12aeaffd6
--- /dev/null
+++ b/browser/extensions/pocket/test/browser_pocket_ui_check.js
@@ -0,0 +1,61 @@
+"use strict";
+
+function checkWindowProperties(expectPresent, l) {
+ for (let name of l) {
+ is(!!window.hasOwnProperty(name), expectPresent, "property " + name + (expectPresent ? " is" : " is not") + " present");
+ }
+}
+function checkElements(expectPresent, l) {
+ for (let id of l) {
+ is(!!document.getElementById(id), expectPresent, "element " + id + (expectPresent ? " is" : " is not") + " present");
+ }
+}
+
+add_task(function* test_setup() {
+ let clearValue = Services.prefs.prefHasUserValue("extensions.pocket.enabled");
+ let enabledOnStartup = Services.prefs.getBoolPref("extensions.pocket.enabled");
+ registerCleanupFunction(() => {
+ if (clearValue) {
+ Services.prefs.clearUserPref("extensions.pocket.enabled");
+ } else {
+ Services.prefs.setBoolPref("extensions.pocket.enabled", enabledOnStartup);
+ }
+ });
+});
+
+add_task(function*() {
+ yield promisePocketEnabled();
+
+ checkWindowProperties(true, ["Pocket", "pktUI", "pktUIMessaging"]);
+ checkElements(true, ["pocket-button", "panelMenu_pocket", "menu_pocket", "BMB_pocket",
+ "panelMenu_pocketSeparator", "menu_pocketSeparator",
+ "BMB_pocketSeparator"]);
+
+ // check context menu exists
+ info("checking content context menu");
+ let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "https://example.com/browser/browser/extensions/pocket/test/test.html");
+
+ let contextMenu = document.getElementById("contentAreaContextMenu");
+ let popupShown = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
+ let popupHidden = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
+ yield BrowserTestUtils.synthesizeMouseAtCenter("body", {
+ type: "contextmenu",
+ button: 2
+ }, tab.linkedBrowser);
+ yield popupShown;
+
+ checkElements(true, ["context-pocket", "context-savelinktopocket"]);
+
+ contextMenu.hidePopup();
+ yield popupHidden;
+ yield BrowserTestUtils.removeTab(tab);
+
+ yield promisePocketDisabled();
+
+ checkWindowProperties(false, ["Pocket", "pktUI", "pktUIMessaging"]);
+ checkElements(false, ["pocket-button", "panelMenu_pocket", "menu_pocket", "BMB_pocket",
+ "panelMenu_pocketSeparator", "menu_pocketSeparator",
+ "BMB_pocketSeparator", "context-pocket", "context-savelinktopocket"]);
+
+ yield promisePocketReset();
+});
diff --git a/browser/extensions/pocket/test/head.js b/browser/extensions/pocket/test/head.js
new file mode 100644
index 000000000..e044a42c7
--- /dev/null
+++ b/browser/extensions/pocket/test/head.js
@@ -0,0 +1,67 @@
+// Currently Pocket is disabled in tests. We want these tests to work under
+// either case that Pocket is disabled or enabled on startup of the browser,
+// and that at the end we're reset to the correct state.
+let enabledOnStartup = false;
+
+// PocketEnabled/Disabled promises return true if it was already
+// Enabled/Disabled, and false if it need to Enable/Disable.
+function promisePocketEnabled() {
+ if (Services.prefs.getPrefType("extensions.pocket.enabled") != Services.prefs.PREF_INVALID &&
+ Services.prefs.getBoolPref("extensions.pocket.enabled")) {
+ info( "pocket was already enabled, assuming enabled by default for tests");
+ enabledOnStartup = true;
+ return Promise.resolve(true);
+ }
+ info( "pocket is not enabled");
+ return new Promise((resolve, reject) => {
+ let listener = {
+ onWidgetAfterCreation(widgetid) {
+ if (widgetid == "pocket-button") {
+ info("pocket-button created");
+ CustomizableUI.removeListener(listener);
+ resolve(false);
+ }
+ }
+ }
+ CustomizableUI.addListener(listener);
+ Services.prefs.setBoolPref("extensions.pocket.enabled", true);
+ });
+}
+
+function promisePocketDisabled() {
+ if (Services.prefs.getPrefType("extensions.pocket.enabled") == Services.prefs.PREF_INVALID ||
+ !Services.prefs.getBoolPref("extensions.pocket.enabled")) {
+ info("pocket-button already disabled");
+ return Promise.resolve(true);
+ }
+ return new Promise((resolve, reject) => {
+ let listener = {
+ onWidgetDestroyed: function(widgetid) {
+ if (widgetid == "pocket-button") {
+ CustomizableUI.removeListener(listener);
+ info( "pocket-button destroyed");
+ // wait for a full unload of pocket
+ BrowserTestUtils.waitForCondition(() => {
+ return !window.hasOwnProperty("pktUI");
+ }, "pocket properties removed from window").then(() => {
+ resolve(false);
+ })
+ }
+ }
+ }
+ CustomizableUI.addListener(listener);
+ info("reset pocket enabled pref");
+ // testing/profiles/prefs_general.js uses user_pref to disable pocket, set
+ // back to false.
+ Services.prefs.setBoolPref("extensions.pocket.enabled", false);
+ });
+}
+
+function promisePocketReset() {
+ if (enabledOnStartup) {
+ info("reset is enabling pocket addon");
+ return promisePocketEnabled();
+ }
+ info("reset is disabling pocket addon");
+ return promisePocketDisabled();
+}
diff --git a/browser/extensions/pocket/test/test.html b/browser/extensions/pocket/test/test.html
new file mode 100644
index 000000000..aa08cd566
--- /dev/null
+++ b/browser/extensions/pocket/test/test.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+ <title>Page Title</title>
+ <meta charset="utf-8" />
+</head>
+
+<body>
+</body>
+</html>