diff options
163 files changed, 7507 insertions, 2071 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml index c14909783..ee2054130 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -6,12 +6,28 @@ workflows: jobs: - prep-deps-npm - prep-deps-firefox + - prep-build: + requires: + - prep-deps-npm - prep-scss: requires: - prep-deps-npm - test-lint: requires: - prep-deps-npm + - test-e2e: + requires: + - prep-deps-npm + - prep-build + - job-screens: + requires: + - prep-deps-npm + - prep-build + - job-publish: + requires: + - prep-deps-npm + - prep-build + - job-screens - test-unit: requires: - prep-deps-npm @@ -33,6 +49,16 @@ workflows: - prep-deps-npm - prep-deps-firefox - prep-scss + - all-tests-pass: + requires: + - test-lint + - test-unit + - test-e2e + - job-screens + - test-integration-mascara-chrome + - test-integration-mascara-firefox + - test-integration-flat-chrome + - test-integration-flat-firefox jobs: prep-deps-npm: @@ -41,7 +67,7 @@ jobs: steps: - checkout - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} + key: dependency-cache-{{ .Revision }} - run: name: Install deps via npm command: npm install @@ -49,6 +75,10 @@ jobs: key: dependency-cache-{{ checksum "package-lock.json" }} paths: - node_modules + - save_cache: + key: dependency-cache-{{ .Revision }} + paths: + - node_modules prep-deps-firefox: docker: @@ -65,6 +95,24 @@ jobs: paths: - firefox + prep-build: + docker: + - image: circleci/node:8-browsers + steps: + - checkout + - restore_cache: + key: dependency-cache-{{ .Revision }} + - run: + name: build:dist + command: npm run dist + - run: + name: build:debug + command: find dist/ -type f -exec md5sum {} \; | sort -k 2 + - save_cache: + key: build-cache-{{ .Revision }} + paths: + - dist + - builds prep-scss: docker: @@ -72,7 +120,7 @@ jobs: steps: - checkout - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} + key: dependency-cache-{{ .Revision }} - run: name: Get Scss Cache key # this allows us to checksum against a whole directory @@ -91,18 +139,81 @@ jobs: steps: - checkout - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} + key: dependency-cache-{{ .Revision }} - run: name: Test command: npm run lint + test-e2e: + docker: + - image: circleci/node:8-browsers + steps: + - checkout + - restore_cache: + key: dependency-cache-{{ .Revision }} + - restore_cache: + key: build-cache-{{ .Revision }} + - run: + name: Test + command: npm run test:e2e + - store_artifacts: + path: test-artifacts + destination: test-artifacts + + job-screens: + docker: + - image: circleci/node:8-browsers + steps: + - checkout + - restore_cache: + key: dependency-cache-{{ .Revision }} + - restore_cache: + key: build-cache-{{ .Revision }} + - run: + name: Test + command: npm run test:screens + - save_cache: + key: job-screens-{{ .Revision }} + paths: + - test-artifacts + + job-publish: + docker: + - image: circleci/node:8-browsers + steps: + - checkout + - restore_cache: + key: dependency-cache-{{ .Revision }} + - restore_cache: + key: build-cache-{{ .Revision }} + - restore_cache: + key: job-screens-{{ .Revision }} + - store_artifacts: + path: dist/mascara + destination: builds/mascara + - store_artifacts: + path: dist/sourcemaps + destination: builds/sourcemaps + - store_artifacts: + path: builds + destination: builds + - store_artifacts: + path: test-artifacts + destination: test-artifacts + - run: + name: build:announce + command: ./development/metamaskbot-build-announce.js + - run: + name: sentry sourcemaps upload + command: npm run sentry:publish + test-unit: docker: - image: circleci/node:8-browsers steps: - checkout - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} + key: dependency-cache-{{ .Revision }} - run: name: test:coverage command: npm run test:coverage @@ -124,7 +235,7 @@ jobs: && sudo mv /usr/bin/firefox /usr/bin/firefox-old && sudo ln -s /opt/firefox58/firefox /usr/bin/firefox - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} + key: dependency-cache-{{ .Revision }} - run: name: Get Scss Cache key # this allows us to checksum against a whole directory @@ -143,7 +254,7 @@ jobs: steps: - checkout - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} + key: dependency-cache-{{ .Revision }} - run: name: Get Scss Cache key # this allows us to checksum against a whole directory @@ -171,7 +282,7 @@ jobs: && sudo mv /usr/bin/firefox /usr/bin/firefox-old && sudo ln -s /opt/firefox58/firefox /usr/bin/firefox - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} + key: dependency-cache-{{ .Revision }} - run: name: Get Scss Cache key # this allows us to checksum against a whole directory @@ -190,7 +301,7 @@ jobs: steps: - checkout - restore_cache: - key: dependency-cache-{{ checksum "package-lock.json" }} + key: dependency-cache-{{ .Revision }} - run: name: Get Scss Cache key # this allows us to checksum against a whole directory @@ -200,3 +311,11 @@ jobs: - run: name: test:integration:mascara command: npm run test:mascara + + all-tests-pass: + docker: + - image: circleci/node:8-browsers + steps: + - run: + name: All Tests Passed + command: echo 'weew - everything passed!' @@ -29,7 +29,8 @@ "plugins": [ "mocha", "chai", - "react" + "react", + "json" ], "globals": { @@ -41,6 +42,7 @@ }, "rules": { + "no-restricted-globals": ["error", "event"], "accessor-pairs": 2, "arrow-spacing": [2, { "before": true, "after": true }], "block-spacing": [2, "always"], diff --git a/.gitignore b/.gitignore index f2a678777..dee5ec220 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,8 @@ test/background.js test/bundle.js test/test-bundle.js +test-artifacts + #ignore css output and sourcemaps ui/app/css/output/ diff --git a/CHANGELOG.md b/CHANGELOG.md index fa4493278..95aebf37d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,22 @@ ## Current Master +## 4.5.2 Wed Apr 04 2018 + +- Fix overly strict validation where transactions were rejected with hex encoded "chainId" + +## 4.5.1 Tue Apr 03 2018 + +- Fix default network (should be mainnet not Rinkeby) +- Fix Sentry automated error reporting endpoint + +## 4.5.0 Mon Apr 02 2018 + +- (beta ui) Internationalization: Select your preferred language in the settings screen +- Internationalization: various locale improvements +- Fix bug where the "Reset account" feature would not clear the network cache. +- Increase maximum gas limit, to allow very gas heavy transactions, since block gas limits have been stable. + ## 4.4.0 Mon Mar 26 2018 - Internationalization: Taiwanese, Thai, Slovenian diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index 0bdce516c..1d2619672 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -14,9 +14,15 @@ "address": { "message": "Adresse" }, + "addCustomToken": { + "message": "Eigenen Token hinzufügen" + }, "addToken": { "message": "Token hinzufügen" }, + "addTokens": { + "message": "Token hinzufügen" + }, "amount": { "message": "Betrag" }, @@ -31,9 +37,15 @@ "message": "MetaMask", "description": "Der Name der Erweiterung" }, + "approved": { + "message": "Genehmigt" + }, "attemptingConnect": { "message": "Versuch mit der Blockchain zu verbinden." }, + "attributions": { + "message": "Was wir verwenden" + }, "available": { "message": "Verfügbar" }, @@ -43,6 +55,9 @@ "balance": { "message": "Guthaben:" }, + "balances": { + "message": "Deine Guthaben" + }, "balanceIsInsufficientGas": { "message": "Guthaben unzureichend für den aktuellen gesamten Gasbetrag" }, @@ -69,7 +84,7 @@ "message": "Auf Coinbase kaufen" }, "buyCoinbaseExplainer": { - "message": "Coinbase ist die weltweit bekannteste Möglichkeit bitcoin, ethereum und litecoin zu kaufen und verkaufen." + "message": "Coinbase ist die weltweit bekannteste Art und Weise um bitcoin, ethereum und litecoin zu kaufen und verkaufen." }, "ok": { "message": "Ok" @@ -105,7 +120,7 @@ "message": "Zu Coinbase fortfahren" }, "contractDeployment": { - "message": "Smart Contract ausführen" + "message": "Smart Contract Ausführung" }, "conversionProgress": { "message": "Umtausch in Arbeit" @@ -148,7 +163,7 @@ "description": "Börsentyp (Kryptowährungen)" }, "currentConversion": { - "message": "Aktueller Umtausch" + "message": "Aktuelle Tauschwährung" }, "currentNetwork": { "message": "Aktuelles Netzwerk" @@ -185,7 +200,7 @@ "description": "Teilt dem Benutzer mit welchen Token er beim Einzahlen mit Shapeshift ausgewählt hat" }, "depositEth": { - "message": "Eth einzahlen" + "message": "Eth kaufen" }, "depositEther": { "message": "Ether einzahlen" @@ -217,7 +232,7 @@ "done": { "message": "Fertig" }, - "downloadStatelogs": { + "downloadStateLogs": { "message": "Statelogs herunterladen" }, "dropped": { @@ -274,7 +289,7 @@ "message": "Folge uns auf Twitter" }, "from": { - "message": "von" + "message": "Von" }, "fromToSame": { "message": "Ziel- und Ursprungsadresse dürfen nicht identisch sein" @@ -347,14 +362,14 @@ "message": "Es erlaubt dir ether & Token zu halten und dient dir als Verbindung zu dezentralisierten Applikationen." }, "import": { - "message": "Import", + "message": "Importieren", "description": "Button um den Account aus einer ausgewählten Datei zu importieren" }, "importAccount": { "message": "Account importieren" }, "importAccountMsg": { - "message":" Importierte Accounts werden nicht mit der Seed Wörterfolge deines ursprünglichen MetaMask Accounts verknüpft. Erfahre mehr über importierte Accounts." + "message":" Importierte Accounts werden nicht mit der Seed-Wörterfolge deines ursprünglichen MetaMask Accounts verknüpft. Erfahre mehr über importierte Accounts." }, "importAnAccount": { "message": "Einen Account importieren" @@ -369,7 +384,7 @@ "infoHelp": { "message": "Info & Hilfe" }, - "insufficientFunds": { + "insufficientFunds": { "message": "Nicht genügend Guthaben." }, "insufficientTokens": { @@ -441,10 +456,10 @@ "message": "Frei" }, "loweCaseWords": { - "message": "Die Wörter der Seed Wörterfolgen sind alle kleingeschrieben" + "message": "Die Wörter der Seed-Wörterfolgen sind alle kleingeschrieben" }, "mainnet": { - "message": "Ethereum Hauptnetzwerk (Main Net)" + "message": "Ethereum Main Net" }, "message": { "message": "Nachricht" @@ -541,7 +556,7 @@ "description": "Für den Import eine Accounts mit Hilfe eines Private Keys" }, "pasteSeed": { - "message": "Füge deine Seed Wörterfolge hier ein!" + "message": "Füge deine Seed-Wörterfolge hier ein!" }, "personalAddressDetected": { "message": "Personalisierte Adresse identifiziert. Bitte füge die Token Contract Adresse ein." @@ -557,7 +572,7 @@ "description": "Wähle diesen Dateityp um damit einen Account zu importieren" }, "privateKeyWarning": { - "message": "Warnung: Niemals jemanden deinen Private Key mitteilen. Jeder der im Besitz deines Private Keys ist, kann jegliches Guthaben deines Accounts stehlen." + "message": "Warnung: Niemals jemanden deinen Private Key mitteilen. Jeder der im Besitz deines Private Keys ist, kann jegliches Guthaben deines Accounts stehlen." }, "privateNetwork": { "message": "Privates Netzwerk" @@ -566,7 +581,7 @@ "message": "QR Code anzeigen" }, "readdToken": { - "message": "Du kannst diesen Token zukünftig wieder hinzufügen indem du in den Menüpunkt \"Token hinzufügen\" in den Einstellungen deines Accounts gehst." + "message": "Du kannst diesen Token immer erneut hinzufügen, indem du in den Menüpunkt \"Token hinzufügen\" in den Einstellungen deines Accounts gehst." }, "readMore": { "message": "Hier mehr erfahren." @@ -590,7 +605,7 @@ "message": "Account zurücksetzten" }, "restoreFromSeed": { - "message": "Mit Hilfe der Seed Wörterfolge wiederherstellen." + "message": "Mit Hilfe der Seed-Wörterfolge wiederherstellen." }, "restoreVault": { "message": "Vault wiederherstellen" @@ -605,13 +620,13 @@ "message": "Wallet Seed" }, "revealSeedWords": { - "message": "Seed Wörterfolge anzeigen" + "message": "Seed-Wörterfolge anzeigen" }, "revealSeedWordsWarning": { - "message": "Bitte niemals deine Seed Wörterfolge an einem öffentlichen Ort kenntlich machen. Mit diesen Wörtern können alle deine Accounts gestohlen werden." + "message": "Bitte niemals deine Seed-Wörterfolge an einem öffentlichen Ort kenntlich machen. Mit diesen Wörtern können alle deine Accounts gestohlen werden." }, "revert": { - "message": "Zurück gehen" + "message": "Rückgängig machen" }, "rinkeby": { "message": "Rinkeby Testnetzwerk" @@ -623,7 +638,7 @@ "message": "Aktueller RPC" }, "connectingToMainnet": { - "message": "Verbinde zum Ethereum Hauptnetzwerk (Main Net)" + "message": "Verbinde zum Ethereum Main Net" }, "connectingToRopsten": { "message": " Verbinde zum Ropsten Testnetzwerk" @@ -649,7 +664,7 @@ "description": "Prozess des Exportieren eines Accounts" }, "saveSeedAsFile": { - "message": "Seed Wörterfolge als Datei speichern" + "message": "Seed-Wörterfolge als Datei speichern" }, "search": { "message": "Suche" @@ -661,7 +676,7 @@ "message": "Neues Passwort (min. 8 Zeichen)" }, "seedPhraseReq": { - "message": "Seed Wörterfolgen bestehen aus 12 Wörtern" + "message": "Seed-Wörterfolgen bestehen aus 12 Wörtern" }, "select": { "message": "Auswählen" @@ -685,7 +700,7 @@ "message": "Token senden" }, "onlySendToEtherAddress": { - "message": "ETH nur zu einer Ethereum Adresse senden." + "message": "ETH unbedingt nur zu einer Ethereum Adresse senden." }, "sendTokensAnywhere": { "message": "Token zu einer beliebigen Person mit einem Ethereumaccount senden" @@ -742,7 +757,7 @@ "message": "Einreichen" }, "submitted": { - "message": "Eingereicht" + "message": "Abgeschickt" }, "supportCenter": { "message": "Gehe zu unserem Support Center" @@ -782,7 +797,7 @@ "message": "Tokensymbol" }, "tokenWarning1": { - "message": "Behalte die Token die du mit deinem MetaMask Account gekauft hast im Auge. Wenn du Token mit einem anderen Account gekauft hast, werden diese hier nicht angezeigt." + "message": "Behalte die Token die du mit deinem MetaMask Account gekauft hast im Blick. Wenn du Token mit einem anderen Account gekauft hast, werden diese hier nicht angezeigt." }, "total": { "message": "Gesamt" @@ -853,7 +868,7 @@ "message": " Account einsehen" }, "visitWebSite": { - "message": "Gehe zu unsere Webseite" + "message": "Gehe zu unserer Webseite" }, "warning": { "message": "Warnung" diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 0bfa992b4..b372326ee 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -56,7 +56,7 @@ "message": "Balance:" }, "balances": { - "message": "Your balances" + "message": "Token balance(s)" }, "balanceIsInsufficientGas": { "message": "Insufficient balance for current gas total" @@ -185,7 +185,7 @@ }, "decimal": { "message": "Decimals of Precision" - }, + }, "defaultNetwork": { "message": "The default network for Ether transactions is Main Net." }, @@ -235,7 +235,7 @@ "done": { "message": "Done" }, - "downloadStatelogs": { + "downloadStateLogs": { "message": "Download State Logs" }, "dropped": { @@ -671,6 +671,12 @@ "save": { "message": "Save" }, + "reprice_title": { + "message": "Reprice Transaction" + }, + "reprice_subtitle": { + "message": "Increase your gas price to attempt to overwrite and speed up your transaction" + }, "saveAsFile": { "message": "Save as File", "description": "Account export process" @@ -820,6 +826,9 @@ "transactions": { "message": "transactions" }, + "transactionError": { + "message": "Transaction Error. Exception thrown in contract code." + }, "transactionMemo": { "message": "Transaction memo (optional)" }, @@ -884,7 +893,7 @@ }, "visitWebSite": { "message": "Visit our web site" - }, + }, "warning": { "message": "Warning" }, diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index fa28b09da..f287674f1 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -247,7 +247,7 @@ "done": { "message": "Completo" }, - "downloadStatelogs": { + "downloadStateLogs": { "message": "Descargar logs de estado" }, "dropped": { diff --git a/app/_locales/hn/messages.json b/app/_locales/hn/messages.json index 3703faa13..323f4b4b3 100644 --- a/app/_locales/hn/messages.json +++ b/app/_locales/hn/messages.json @@ -223,7 +223,7 @@ "done": { "message": "संपन्न" }, - "downloadStatelogs": { + "downloadStateLogs": { "message": "राज्य लॉग डाउनलोड करें" }, "edit": { diff --git a/app/_locales/index.json b/app/_locales/index.json new file mode 100644 index 000000000..c085deb72 --- /dev/null +++ b/app/_locales/index.json @@ -0,0 +1,19 @@ +[ + { "code": "de", "name": "German" }, + { "code": "en", "name": "English" }, + { "code": "es", "name": "Spanish" }, + { "code": "fr", "name": "French" }, + { "code": "hn", "name": "Hindi" }, + { "code": "it", "name": "Italian" }, + { "code": "ja", "name": "Japanese" }, + { "code": "ko", "name": "Korean" }, + { "code": "nl", "name": "Dutch" }, + { "code": "ph", "name": "Tagalog" }, + { "code": "pt", "name": "Portuguese" }, + { "code": "ru", "name": "Russian" }, + { "code": "sl", "name": "Slovenian" }, + { "code": "th", "name": "Thai" }, + { "code": "vi", "name": "Vietnamese" }, + { "code": "zh_CN", "name": "Mandarin" }, + { "code": "zh_TW", "name": "Taiwanese" } +] diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json index f54ef98ca..ef3ed4025 100644 --- a/app/_locales/it/messages.json +++ b/app/_locales/it/messages.json @@ -223,7 +223,7 @@ "done": { "message": "Finito" }, - "downloadStatelogs": { + "downloadStateLogs": { "message": "Scarica i log di Stato" }, "edit": { diff --git a/app/_locales/nl/messages.json b/app/_locales/nl/messages.json index aacb81fee..38289f602 100644 --- a/app/_locales/nl/messages.json +++ b/app/_locales/nl/messages.json @@ -223,7 +223,7 @@ "done": { "message": "Gedaan" }, - "downloadStatelogs": { + "downloadStateLogs": { "message": "Staatslogboeken downloaden" }, "edit": { @@ -299,7 +299,7 @@ "message": "De gaslimiet moet minstens 21000 zijn" }, "generatingSeed": { - "message": "Zaad produceren ..." + "message": "Back-up woorden produceren ..." }, "gasPrice": { "message": "Gasprijs (GWEI)" @@ -432,7 +432,7 @@ "message": "Los" }, "loweCaseWords": { - "message": "zaadwoorden hebben alleen kleine letters" + "message": "back-up woorden hebben alleen kleine letters" }, "mainnet": { "message": "belangrijkste ethereum-netwerk" @@ -532,7 +532,7 @@ "description": "Voor het importeren van een account vanaf een privésleutel" }, "pasteSeed": { - "message": "Plak je zaadzin hier!" + "message": "Plak je back-up woorden hier!" }, "personalAddressDetected": { "message": "Persoonlijk adres gedetecteerd. Voer het tokencontractadres in." @@ -581,7 +581,7 @@ "message": "Account opnieuw instellen" }, "restoreFromSeed": { - "message": "Herstel van zaaduitdrukking" + "message": "Herstel vanuit back-up woorden" }, "required": { "message": "Verplicht" @@ -590,10 +590,10 @@ "message": "Probeer hier opnieuw met een hogere gasprijs" }, "revealSeedWords": { - "message": "Onthul zaadwoorden" + "message": "Onthul back-up woorden" }, "revealSeedWordsWarning": { - "message": "Herstel je zaadwoorden niet op een openbare plaats! Deze woorden kunnen worden gebruikt om al uw accounts te stelen." + "message": "Zorg dat je back-up woorden niet op een openbare plaats bekijkt! Deze woorden kunnen worden gebruikt om al uw accounts opnieuw te genereren (en dus uw account te stelen)." }, "revert": { "message": "terugkeren" @@ -616,7 +616,7 @@ "description": "Account export proces" }, "saveSeedAsFile": { - "message": "Bewaar zaadwoorden als bestand" + "message": "Bewaar back-up woorden als bestand" }, "search": { "message": "Zoeken" @@ -625,7 +625,7 @@ "message": "Voer hier je geheime twaalfwoordfrase in om je kluis te herstellen." }, "seedPhraseReq": { - "message": "zaadzinnen zijn 12 woorden lang" + "message": "Back-up woorden zijn 12 woorden lang" }, "select": { "message": "kiezen" diff --git a/app/_locales/pt/messages.json b/app/_locales/pt/messages.json index c9eb178f9..e770392d0 100644 --- a/app/_locales/pt/messages.json +++ b/app/_locales/pt/messages.json @@ -223,7 +223,7 @@ "done": { "message": "Finalizado" }, - "downloadStatelogs": { + "downloadStateLogs": { "message": "Descarregar Registos de Estado" }, "edit": { diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index e3a1935f5..b43251064 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -3,13 +3,13 @@ "message": "Принять" }, "account": { - "message": "Аккаунт" + "message": "Счет" }, "accountDetails": { - "message": "Детали Аккаунта" + "message": "Детали счета" }, "accountName": { - "message": "Имя Пользователя" + "message": "Название счета" }, "address": { "message": "Адрес" @@ -21,13 +21,13 @@ "message": "Добавить токен" }, "addTokens": { - "message": "Добавить Токены" + "message": "Добавить токены" }, "amount": { - "message": "Количество" + "message": "Сумма" }, "amountPlusGas": { - "message": "Количество + газ" + "message": "Сумма + газ" }, "appDescription": { "message": "Расширение браузера для Ethereum", @@ -37,11 +37,14 @@ "message": "MetaMask", "description": "The name of the application" }, + "approved": { + "message": "Одобрена" + }, "attemptingConnect": { "message": "Попытка подключиться к блокчейн сети." }, "attributions": { - "message": "Опознания" + "message": "Атрибуция" }, "available": { "message": "Доступный" @@ -53,13 +56,13 @@ "message": "Баланс:" }, "balances": { - "message": "Ваши балансы" + "message": "Ваш баланс" }, "balanceIsInsufficientGas": { "message": "Недостаточный баланс для текущего объема газа" }, "beta": { - "message": "БЕТА" + "message": "BETA" }, "betweenMinAndMax": { "message": "должно быть больше или равно $1 и меньше или равно $2.", @@ -69,10 +72,10 @@ "message": "Использовать Blockies Identicon" }, "borrowDharma": { - "message": "Заимствовать с Dharma (бета)" + "message": "Взять в долг на Dharma (Beta)" }, "builtInCalifornia": { - "message": "MetaMask спроектирован и построен в Калифорнии." + "message": "MetaMask спроектирован и разработан в Калифорнии." }, "buy": { "message": "Купить" @@ -81,7 +84,10 @@ "message": "Купить на Coinbase" }, "buyCoinbaseExplainer": { - "message": "Coinbase - самый популярный в мире способ купить и продать биткойн, ethereum и litecoin." + "message": "Биржа Coinbase – это наиболее популярный способ купить или продать bitcoin, ethereum и litecoin." + }, + "ok": { + "message": "ОК" }, "cancel": { "message": "Отмена" @@ -95,14 +101,17 @@ "confirm": { "message": "Подтвердить" }, + "confirmed": { + "message": "Подтверждена" + }, "confirmContract": { - "message": "Подтвердить Контракт" + "message": "Подтвердить контракт" }, "confirmPassword": { - "message": "Подтвердите Пароль" + "message": "Подтвердите пароль" }, "confirmTransaction": { - "message": "Подтвердить Транзакцию" + "message": "Подтвердить транзакцию" }, "continue": { "message": "Продолжить" @@ -114,7 +123,7 @@ "message": "Развертывание контракта" }, "conversionProgress": { - "message": "Выполняется конверсия" + "message": "Выполняется конвертация" }, "copiedButton": { "message": "Скопировано" @@ -126,7 +135,7 @@ "message": "Скопировано!" }, "copiedSafe": { - "message": "Я скопировал его где-то в безопасности" + "message": "Я скопировал это в безопасное место" }, "copy": { "message": "Скопировать" @@ -138,29 +147,32 @@ "message": " Скопировать " }, "copyPrivateKey": { - "message": "Это ваш личный ключ (нажмите, чтобы скопировать)" + "message": "Это ваш закрытый ключ (нажмите, чтобы скопировать)" }, "create": { "message": "Создать" }, "createAccount": { - "message": "Регистрация" + "message": "Создать счет" }, "createDen": { "message": "Создать" }, "crypto": { - "message": "Крипто", + "message": "Криптовалюта", "description": "Exchange type (cryptocurrencies)" }, "currentConversion": { - "message": "Текущая конверсия" + "message": "Текущая конвертация" }, "currentNetwork": { "message": "Текущая сеть" }, "customGas": { - "message": "Настроить Газ" + "message": "Настроить газ" + }, + "customToken": { + "message": "Пользовательский токен" }, "customize": { "message": "Настроить" @@ -169,112 +181,115 @@ "message": "Пользовательский RPC" }, "decimalsMustZerotoTen": { - "message": "Десятичные числа должны быть не менее 0, и не более 36." + "message": "Количество десятичных разрядов должно быть минимум 0 и максимум 36." }, "decimal": { - "message": "Десятичные значения точности" + "message": "Количество десятичных разрядов" }, "defaultNetwork": { - "message": "Сеть по умолчанию для транзакций Ether - это Main Net." + "message": "Основная сеть Ethereum – это сеть по умолчанию для Ether транзакций." }, "denExplainer": { - "message": "Ваш DEN - это ваше зашифрованное паролем хранилище в MetaMask." + "message": "DEN – это зашифрованное паролем хранилище внутри MetaMask." }, "deposit": { - "message": "Депозит" + "message": "Пополнить" }, "depositBTC": { - "message": "Депозит BTC по адресу:" + "message": "Отправьте ваш BTC на адрес ниже:" }, "depositCoin": { - "message": "Депозит $1 по указанному ниже адресу", + "message": "Отправьте ваш $1 на адрес ниже", "description": "Tells the user what coin they have selected to deposit with shapeshift" }, "depositEth": { - "message": "Депозит Eth" + "message": "Пополнить Eth" }, "depositEther": { - "message": "Депозит Эфир" + "message": "Пополнить Ether" }, "depositFiat": { - "message": "Депозит с деньгами" + "message": "Пополнить деньгами" }, "depositFromAccount": { - "message": "Депозит с другого счета" + "message": "Пополнить с другого счета" }, "depositShapeShift": { - "message": "Депозит с ShapeShift" + "message": "Пополнить через ShapeShift" }, "depositShapeShiftExplainer": { - "message": "Если у вас есть другие крипторесурсы, вы можете торговать и вносить Эфир непосредственно в кошелек MetaMask. Нет необходимости в аккаунте." + "message": "Если у вас есть другие криптовалюты, вы можете торговать и пополнять Ether напрямую в ваш MetaMask кошелек. Нет необходимости в счете." }, "details": { "message": "Детали" }, "directDeposit": { - "message": "Прямой Депозит" + "message": "Прямое пополнение" }, "directDepositEther": { - "message": "Прямой Депозит Эфира" + "message": "Прямое пополнение Ether" }, "directDepositEtherExplainer": { - "message": "Если у вас уже есть Эфир, самый быстрый способ получить Эфир в вашем новом кошельке это прямым депозитом." + "message": "Если у вас уже есть Ether, то самый быстрый способ получить Ether в ваш новый кошелек – это прямое пополнение." }, "done": { "message": "Готово" }, - "downloadStatelogs": { - "message": "Загрузить логи статус" + "downloadStateLogs": { + "message": "Скачать журнал состояния" + }, + "dropped": { + "message": "Отброшена" }, "edit": { "message": "Редактировать" }, "editAccountName": { - "message": "Изменить Имя Аккаунта" + "message": "Редактировать название счета" }, "emailUs": { "message": "Свяжитесь с нами по электронной почте!" }, "encryptNewDen": { - "message": "Шифруйте новый DEN" + "message": "Зашифровать ваш новый DEN" }, "enterPassword": { "message": "Введите пароль" }, "enterPasswordConfirm": { - "message": "Введите свой пароль для подтверждения" + "message": "Введите ваш пароль для подтверждения" }, "etherscanView": { - "message": "Просмотреть аккаунт на Etherscan" + "message": "Просмотреть счет на Etherscan" }, "exchangeRate": { - "message": "Обменный Курс" + "message": "Обменный курс" }, "exportPrivateKey": { - "message": "Экспорт закрытого ключа" + "message": "Экспортировать закрытый ключ" }, "exportPrivateKeyWarning": { - "message": "Экспорт секретных ключей на свой страх и риск." + "message": "Вы экспортируете закрытые ключи на свой страх и риск." }, "failed": { - "message": "Не смогли" + "message": "Неудачна" }, "fiat": { - "message": "Бумажные деньги", + "message": "Валюта", "description": "Exchange type" }, "fileImportFail": { - "message": "Ошибка импорта файлов? Кликните сюда!", + "message": "Не работает импорт файла? Нажмите тут!", "description": "Helps user import their account from a JSON file" }, "followTwitter": { - "message": "Следуйте за нами на Twitter" + "message": "Читайте нас в Twitter" }, "from": { - "message": "Из" + "message": "Отправитель" }, "fromToSame": { - "message": "От и до адреса не могут быть одинаковым" + "message": "Адрес отправителя и получателя не могут быть одинаковыми" }, "fromShapeShift": { "message": "Из ShapeShift" @@ -284,37 +299,37 @@ "description": "Short indication of gas cost" }, "gasFee": { - "message": "Плата за Газ" + "message": "Комиссия за газ" }, "gasLimit": { - "message": "Газовый Предел" + "message": "Лимит газа" }, "gasLimitCalculation": { - "message": "Мы рассчитываем предполагаемый предел газа на основе коэффициентов успешности сети." + "message": "Мы расчитываем предлагаемый лимит газа на основании успешных ставок в сети." }, "gasLimitRequired": { - "message": "Требуется ограничение на Газ" + "message": "Установите лимит газа" }, "gasLimitTooLow": { - "message": "Предел газа должен быть не менее 21000" + "message": "Лимит газа должен быть как минимум 21000" }, "generatingSeed": { - "message": "Создание Семян ..." + "message": "Генерируем фразу..." }, "gasPrice": { - "message": "Цена на Газ (GWEI)" + "message": "Цена за газ (GWEI)" }, "gasPriceCalculation": { - "message": "Мы вычисляем предлагаемые цены на газ на основе коэффициентов успеха сети." + "message": "Мы расчитываем предлагаемые цены за газ на основании успешных ставок в сети." }, "gasPriceRequired": { - "message": "Требуется цена на Газ" + "message": "Установите стоимость газа" }, "getEther": { - "message": "Получить Эфир" + "message": "Получить Ether" }, "getEtherFromFaucet": { - "message": "Получите Эфир из крана $1", + "message": "Получить Ether из крана для $1", "description": "Displays network name for Ether faucet" }, "greaterThanMin": { @@ -322,14 +337,14 @@ "description": "helper for inputting hex as decimal input" }, "here": { - "message": "здесь", + "message": "тут", "description": "as in -click here- for more information (goes with troubleTokenBalances)" }, "hereList": { - "message": "Вот список !!!!" + "message": "Вот список!!!!" }, "hide": { - "message": "Спрятать" + "message": "Скрыть" }, "hideToken": { "message": "Скрыть токен" @@ -338,33 +353,33 @@ "message": "Скрыть токен?" }, "howToDeposit": { - "message": "Как бы вы хотели поместить Эфир?" + "message": "Как бы вы хотели пополнить Ether?" }, "holdEther": { - "message": "Это позволяет вам использовать эфир и токены и служит мостом для децентрализованных приложений." + "message": "Позволяет вам хранить ether и токены и служит в качестве моста в децентрализированные приложения." }, "import": { "message": "Импортировать", "description": "Button to import an account from a selected file" }, "importAccount": { - "message": "Импорт Аккаунта" + "message": "Импортировать счет" }, "importAccountMsg": { - "message": " Импортированные аккаунты не будут связаны с вашей первоначально созданным аккаунтом MetaMask. Подробнее о импортированных аккаунтах " + "message":" Импортированные счета не будут ассоциированы с вашей ключевой фразой, созданной MetaMask. Узнать больше про импорт счетов " }, "importAnAccount": { "message": "Импортировать аккаунт" }, "importDen": { - "message": "Импорт существующих DEN" + "message": "Импортировать существующий DEN" }, "imported": { "message": "Импортирован", "description": "status showing that an account has been fully loaded into the keyring" }, "infoHelp": { - "message": "Информация и Помощь" + "message": "Информация и помощь" }, "insufficientFunds": { "message": "Недостаточно средств." @@ -373,35 +388,44 @@ "message": "Недостаточно токенов." }, "invalidAddress": { - "message": "Недействительный адрес" + "message": "Неверный адрес" }, "invalidAddressRecipient": { - "message": "Недопустимый адрес получателя." + "message": "Неверный адрес получателя" }, "invalidGasParams": { - "message": "Недопустимые параметры Газа" + "message": "Неверные параметры газа" }, "invalidInput": { - "message": "Неправильный ввод." + "message": "Неверный ввод." }, "invalidRequest": { - "message": "Неверный Запрос" + "message": "Неверный запрос" }, "invalidRPC": { - "message": "Недопустимый URI RPC" + "message": "Неверный RPC URI" }, "jsonFail": { - "message": "Что-то пошло не так. Убедитесь, что ваш файл JSON правильно отформатирован." + "message": "Что-то пошло не так. Убедитесь, что ваш JSON файл правильно отформатирован." }, "jsonFile": { - "message": "Файл JSON", + "message": "JSON файл", "description": "format for importing an account" }, + "keepTrackTokens": { + "message": "Следите за купленными вами токенами с помощью аккаунта MetaMask." + }, "kovan": { - "message": "Kovan тестовая сеть" + "message": "Тестовая сеть Kovan" }, "knowledgeDataBase": { - "message": "Посетите нашу базу знаний" + "message": "Посмотрите нашу Базу Знаний" + }, + "max": { + "message": "Максимум" + }, + "learnMore": { + "message": "Узнать больше." }, "lessThanMax": { "message": "должно быть меньше или равно $1.", @@ -410,29 +434,32 @@ "likeToAddTokens": { "message": "Вы хотите добавить эти токены?" }, + "links": { + "message": "Ссылки" + }, "limit": { - "message": "Предел" + "message": "Лимит" }, "loading": { "message": "Загрузка..." }, "loadingTokens": { - "message": "Загрузка токенов ..." + "message": "Загрузка токенов..." }, "localhost": { - "message": "Локальный адрес 8545" + "message": "Localhost 8545" }, "login": { - "message": "Авторизоваться" + "message": "Вход" }, "logout": { - "message": "Выйти" + "message": "Выход" }, "loose": { - "message": "Рыхлый" + "message": "Несвязанный" }, "loweCaseWords": { - "message": "семенные слова имеют только символы нижнего регистра" + "message": "ключевая фраза может содержать только символы нижнего регистра" }, "mainnet": { "message": "Основная сеть Ethereum" @@ -441,19 +468,19 @@ "message": "Сообщение" }, "metamaskDescription": { - "message": "MetaMask - это безопасное хранилище для Ethereum." + "message": "MetaMask – безопасный кошелек для Ethereum." }, "min": { "message": "Минимум" }, "myAccounts": { - "message": "Мои Аккаунты" + "message": "Мои счета" }, "mustSelectOne": { - "message": "Необходимо выбрать не менее 1 токена." + "message": "Необходимо выбрать как минимум 1 токен." }, "needEtherInWallet": { - "message": "Чтобы взаимодействовать с децентрализованными приложениями с помощью MetaMask, вам понадобится Эфир в вашем кошельке." + "message": "Для взаимодействия с децентрализованными приложениями с помощью MetaMask нужен Ether в вашем кошельке." }, "needImportFile": { "message": "Вы должны выбрать файл для импорта.", @@ -464,60 +491,60 @@ "description": "Password and file needed to import an account" }, "negativeETH": { - "message": "Невозможно отправить отрицательные количества ETH." + "message": "Невозможно отправить отрицательную сумму ETH." }, "networks": { "message": "Сети" }, "newAccount": { - "message": "Новый Аккаунт" + "message": "Новый счет" }, "newAccountNumberName": { - "message": "Аккаунт $1", + "message": "Счет $1", "description": "Default name of next account to be created on create account screen" }, "newContract": { - "message": "Новый Контракт" + "message": "Новый контракт" }, "newPassword": { "message": "Новый пароль (мин. 8 символов)" }, "newRecipient": { - "message": "Новый Получатель" + "message": "Новый получатель" }, "newRPC": { - "message": "Новый URL-адрес RPC" + "message": "Новый RPC URL" }, "next": { "message": "Далее" }, "noAddressForName": { - "message": "Для этого имени не задан адрес." + "message": "Дла этого названия не установлен адрес." }, "noDeposits": { - "message": "Не было получено никаких депозитов" + "message": "Пополнения не получены" }, "noTransactionHistory": { "message": "Нет истории транзакций." }, "noTransactions": { - "message": "Нет Транзакций" + "message": "Нет транзакций" }, "notStarted": { - "message": "Не Начался" + "message": "Не запущен" }, "oldUI": { - "message": "Старый Интерфейс" + "message": "Старая версия интерфейса" }, "oldUIMessage": { - "message": "Вы вернулись к старому интерфейсу. Вы можете вернуться к новому с помощью опции в раскрывающемся меню в правом верхнем углу." + "message": "Вы вернулись к старой версии интерфейса пользователя. Вы можете переключиться на новую с помощью опции выпадающего меню в правом верхнем углу." }, "or": { "message": "или", "description": "choice between creating or importing a new account" }, "passwordCorrect": { - "message": "Убедитесь, что ваш пароль правильный." + "message": "Убедитесь, что ваш пароль верный." }, "passwordMismatch": { "message": "пароли не совпадают", @@ -528,27 +555,30 @@ "description": "in password creation process, the password is not long enough to be secure" }, "pastePrivateKey": { - "message": "Вставьте свою личную строку:", + "message": "Вставьте ваш закрытый ключ тут:", "description": "For importing an account from a private key" }, "pasteSeed": { - "message": "Вставьте здесь свою семенную фразу!" + "message": "Вставьте вашу ключевую фразу!" }, "personalAddressDetected": { - "message": "Персональный адрес обнаружен. Введите адрес контракта токена." + "message": "Обнаружен персональный адрес. Введите адрес контракта токена." }, "pleaseReviewTransaction": { "message": "Проверьте транзакцию." }, + "popularTokens": { + "message": "Популярные токены" + }, "privacyMsg": { - "message": "Политика Конфиденциальности" + "message": "Политика конфиденциальности" }, "privateKey": { "message": "Закрытый ключ", "description": "select this type of file to use to import an account" }, "privateKeyWarning": { - "message": "Предупреждение: никогда не раскрывайте этот ключ. Любой, у кого есть ваши личные ключи, может украсть любые активы, хранящиеся в вашем аккаунте." + "message": "Предупреждение: Никогда не раскрывайте этот ключ. Любой, у кого есть ваши закрытые ключи, может украсть любые активы, хранящиеся на счету." }, "privateNetwork": { "message": "Частная сеть" @@ -557,126 +587,165 @@ "message": "Показать QR-код" }, "readdToken": { - "message": "Вы можете добавить этот токен в будущем, перейдя в “Добавить токен” в меню параметров вашего аккаунта." + "message": "Вы можете в будущем добавить обратно этот токен, выбрав пункт меню “Добавить токен”." }, "readMore": { - "message": "Подробнее читайте здесь." + "message": "Узнать больше тут." }, "readMore2": { - "message": "Прочитайте больше." + "message": "Узнать больше." }, "receive": { "message": "Получить" }, "recipientAddress": { - "message": "Адрес Получателя" + "message": "Адрес получателя" }, "refundAddress": { - "message": "Ваш Адрес Возврата" + "message": "Ваш адрес для возврата средств" }, "rejected": { - "message": "Отклонено" + "message": "Отклонена" }, "resetAccount": { "message": "Сбросить аккаунт" }, "restoreFromSeed": { - "message": "Восстановить от семенной фразы" + "message": "Восстановить из ключевой фразы" + }, + "restoreVault": { + "message": "Восстановить кошелек" }, "required": { - "message": "Необходимо" + "message": "Обязательное поле" }, "retryWithMoreGas": { - "message": "Повторите попытку с более высокой ценой на газ здесь" + "message": "Повторите попытку с большей ценой за газRetry with a higher gas price here" + }, + "walletSeed": { + "message": "Ключевая фраза кошелька" }, "revealSeedWords": { - "message": "Раскрыть семенные слова" + "message": "Показать ключевую фразу" }, "revealSeedWordsWarning": { - "message": "Не восстанавливайте семенные слова в общественном месте! Эти слова могут использоваться для кражи всех ваших аккаунтах." + "message": "Не восстанавливайте ключевую фразу в общественном месте! Она может быть использована для кражи всех ваших счетов." }, "revert": { - "message": "Откат" + "message": "Восстановить" }, "rinkeby": { - "message": "Rinkeby тестовая сеть" + "message": "Тестовая сеть Rinkeby" }, "ropsten": { - "message": "Ropsten тестовая сеть" + "message": "Тестовая сеть Ropsten" + }, + "currentRpc": { + "message": "Current RPC" + }, + "connectingToMainnet": { + "message": "Соединение с основной сетью Ethereum" + }, + "connectingToRopsten": { + "message": "Соединение с тестовой сетью Ropsten" + }, + "connectingToKovan": { + "message": "Соединение с тестовой сетью Kovan" + }, + "connectingToRinkeby": { + "message": "Соединение с тестовой сетью Rinkeby" + }, + "connectingToUnknown": { + "message": "Соединение с неизвестной сетью" }, "sampleAccountName": { - "message": "Например, Мой новый аккаунт", + "message": "Например, Мой новый счет", "description": "Help user understand concept of adding a human-readable name to their account" }, "save": { "message": "Сохранить" }, "saveAsFile": { - "message": "Сохранить как Файл", + "message": "Сохранить в виде файла", "description": "Account export process" }, "saveSeedAsFile": { - "message": "Сохранить Семенные Слова Как Файл" + "message": "Сохранить ключевую фразу в виде файла" }, "search": { "message": "Поиск" }, "secretPhrase": { - "message": "Введите свою секретную двенадцатисловную фразу здесь, чтобы восстановить хранилище." + "message": "Введите вашу ключевую фразу из 12 слов, чтобы восстановить кошелек." + }, + "newPassword8Chars": { + "message": "Новый пароль (мин. 8 символов)" }, "seedPhraseReq": { - "message": "семенные фразы длиной 12 слов" + "message": "ключевые фразы имеют длину 12 слов" }, "select": { "message": "Выбрать" }, "selectCurrency": { - "message": "Выберите Валюту" + "message": "Выберите валюту" }, "selectService": { - "message": "Выберите Сервис" + "message": "Выберите сервис" }, "selectType": { - "message": "Выберите Тип" + "message": "Выберите тип" }, "send": { - "message": "Послать" + "message": "Отправить" }, "sendETH": { "message": "Отправить ETH" }, "sendTokens": { - "message": "Отправить Токены" + "message": "Отправить токены" + }, + "onlySendToEtherAddress": { + "message": "Отправляйте ETH только на Ethereum адреса." + }, + "searchTokens": { + "message": "Поиск токенов" }, "sendTokensAnywhere": { - "message": "Отправить Токены кому-либо с аккаунтом Ethereum" + "message": "Отправить токены любому, у кого есть счет Ethereum" }, "settings": { "message": "Настройки" }, + "info": { + "message": "Информация" + }, "shapeshiftBuy": { - "message": "Купить с помощью Shapeshift" + "message": "Купить через Shapeshift" }, "showPrivateKeys": { - "message": "Показать приватные ключи" + "message": "Показать закрытые ключи" }, "showQRCode": { "message": "Показать QR-код" }, "sign": { - "message": "Знак" + "message": "Подпись" + }, + "signed": { + "message": "Подписана" }, "signMessage": { - "message": "Нодписать сообщение" + "message": "Подписать сообщение" }, "signNotice": { - "message": "Подписание этого сообщения может иметь \nопасные побочные эффекты. Только подписывайте сообщения \nс сайтов, которым вы полностью доверяете своим аккаунтом. Этот опасный метод будет удален в будущей версии." + "message": "Подпись этого сообщения может иметь \nопасные побочные эффекты. Подписывайте только сообщения \nс сайтов, которым вы полностью доверяете свой аккаунт. Этот опасный метод будет удален в будущей версии." }, "sigRequest": { - "message": "Запрос на подпись" + "message": "Запрос подписи" }, "sigRequested": { - "message": "Подпись Запрошена" + "message": "Подпись запрошена" }, "spaceBetween": { "message": "между словами может быть только пробел" @@ -685,53 +754,59 @@ "message": "Статус" }, "stateLogs": { - "message": "Логи Статуса" + "message": "Журнал состояния" }, "stateLogsDescription": { - "message": "Логи статуса содержат ваши общедоступные адреса и отправленные транзакции." + "message": "Журнал состояния содержит ваши публичные адреса счетов и совершенные транзакции." + }, + "stateLogError": { + "message": "Ошибка при получении журнала состояния." }, "submit": { "message": "Отправить" }, + "submitted": { + "message": "Отправлена" + }, "supportCenter": { - "message": "Посетите наш Центр поддержки" + "message": "Перейти в наш Центр поддержки" }, "symbolBetweenZeroTen": { "message": "Символ должен быть от 0 до 10 символов." }, "takesTooLong": { - "message": "Занимает слишком долго?" + "message": "Слишком долго?" }, "terms": { - "message": "Условия Эксплуатации" + "message": "Условия пользования" }, "testFaucet": { - "message": "Тестовый Кран" + "message": "Тестовый кран" }, "to": { - "message": "К" + "message": "Получатель: " }, "toETHviaShapeShift": { "message": "$1 в ETH через ShapeShift", "description": "system will fill in deposit type in start of message" }, "tokenAddress": { - "message": "Адрес Токена" + "message": "Адрес токена" }, "tokenAlreadyAdded": { - "message": "Токен уже добавлен." + "message": "Токен уже был добавлен." }, "tokenBalance": { - "message": "Баланс Вашых Tокенов:" + "message": "Баланс ваших токенов:" }, "tokenSelection": { - "message": "Поиск токенов или выбор из нашего списка популярных токенов." + "message": "Поищите токен или выберите из нашего списка популярных токенов." }, "tokenSymbol": { - "message": "Символ Токена" + "message": "Символ токена" }, "tokenWarning1": { - "message": "Следите за токенами, которые вы купили с помощью аккаунта MetaMask. Если вы купили токены, используя другой аккаунт, эти токены здесь не появятся." + "message": "Отслеживаются токены, купленные на счет в MetaMask. Если вы купили токены, используя другой счет, такие токены не будут тут отображены." }, "total": { "message": "Всего" @@ -740,35 +815,38 @@ "message": "транзакции" }, "transactionMemo": { - "message": "Транзакционная записка (необязательно)" + "message": "Транзакционные данные (необязательный)" }, "transactionNumber": { - "message": "Номер Транзакции" + "message": "Номер транзакции" }, "transfers": { "message": "Переводы" }, "troubleTokenBalances": { - "message": "У нас были проблемы с загрузкой ваших токенов. Вы можете просмотреть их ", + "message": "Возникли проблемы при загрузке балансов токенов. Вы можете посмотреть их ", "description": "Followed by a link (here) to view token balances" }, "twelveWords": { - "message": "Эти 12 слов - единственный способ восстановить ваши учетные записи MetaMask.\nСохраните их где-нибудь в безопасности и в тайне." + "message": "Эти 12 слов являются единственной возможностью восстановить ваши счета в MetaMask.\nСохраните из в надежном секретном месте." }, "typePassword": { - "message": "Введите Пароль" + "message": "Введите пароль" }, "uiWelcome": { - "message": "Добро пожаловать в новый интерфейс (бета-версия)" + "message": "Новый интерфейс (Beta)" }, "uiWelcomeMessage": { - "message": "Теперь вы используете новый интерфейс Metamask. Осмотритесь, попробуйте новые функции, такие как отправку токенов, и сообщите нам, есть ли у вас какие-либо проблемы." + "message": "Теперь вы используете новый интерфейс пользователя MetaMask. Осмотритесь, попробуйте новые функции, например, отправить токены и, если возникнут проблемы, сообщите нам." + }, + "unapproved": { + "message": "Не одобрена" }, "unavailable": { - "message": "Недоступен" + "message": "Недоступный" }, "unknown": { - "message": "Неизвестный" + "message": "Неизвестно" }, "unknownNetwork": { "message": "Неизвестная частная сеть" @@ -777,7 +855,7 @@ "message": "Неизвестный идентификатор сети" }, "uriErrorMsg": { - "message": "Для URI требуется соответствующий префикс HTTP / HTTPS." + "message": "Для URI требуется соответствующий префикс HTTP/HTTPS." }, "usaOnly": { "message": "Только США", @@ -787,19 +865,19 @@ "message": "Используется различными клиентами" }, "useOldUI": { - "message": "Использовать старый интерфейс" + "message": "Использовать старый интерфейс пользователя" }, "validFileImport": { - "message": "Вы должны выбрать действительный файл для импорта." + "message": "Вам нужно выбрать правильный файл для импорта." }, "vaultCreated": { - "message": "Создано хранилище" + "message": "Кошелек был создан" }, "viewAccount": { - "message": "Посмотреть аккаунт" + "message": "Посмотреть счет" }, "visitWebSite": { - "message": "Посетите наш сайт" + "message": "Перейти на наш сайт" }, "warning": { "message": "Предупреждение" @@ -811,7 +889,7 @@ "message": "Что это?" }, "yourSigRequested": { - "message": "Ваша подпись запрашивается" + "message": "Запрашивается ваша подпись" }, "youSign": { "message": "Вы подписываете" diff --git a/app/_locales/sl/messages.json b/app/_locales/sl/messages.json index 0532f11b2..b089f3476 100644 --- a/app/_locales/sl/messages.json +++ b/app/_locales/sl/messages.json @@ -223,7 +223,7 @@ "done": { "message": "Končano" }, - "downloadStatelogs": { + "downloadStateLogs": { "message": "Prenesi state dnevnike" }, "edit": { diff --git a/app/_locales/th/messages.json b/app/_locales/th/messages.json index 887714f3f..3d7dec226 100644 --- a/app/_locales/th/messages.json +++ b/app/_locales/th/messages.json @@ -223,7 +223,7 @@ "done": { "message": "เสร็จสิ้น" }, - "downloadStatelogs": { + "downloadStateLogs": { "message": "ดาวน์โหลดล็อกสถานะ" }, "edit": { diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json index e39793430..9aaee0e16 100644 --- a/app/_locales/zh_TW/messages.json +++ b/app/_locales/zh_TW/messages.json @@ -235,7 +235,7 @@ "done": { "message": "完成" }, - "downloadStatelogs": { + "downloadStateLogs": { "message": "下載狀態紀錄" }, "dropped": { diff --git a/app/home.html b/app/home.html index cfb4b00a0..4fad0f993 100644 --- a/app/home.html +++ b/app/home.html @@ -3,10 +3,10 @@ <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1 user-scalable=no"> - <title>MetaMask Plugin</title> + <title>MetaMask</title> </head> <body> <div id="app-content"></div> - <script src="./scripts/popup.js" type="text/javascript" charset="utf-8"></script> + <script src="./ui.js" type="text/javascript" charset="utf-8"></script> </body> </html> diff --git a/app/manifest.json b/app/manifest.json index a20f9b976..2a18bdb2d 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "__MSG_appName__", "short_name": "__MSG_appName__", - "version": "4.4.0", + "version": "4.5.2", "manifest_version": 2, "author": "https://metamask.io", "description": "__MSG_appDescription__", @@ -27,8 +27,8 @@ "default_locale": "en", "background": { "scripts": [ - "scripts/chromereload.js", - "scripts/background.js" + "chromereload.js", + "background.js" ], "persistent": true }, @@ -48,7 +48,7 @@ "https://*/*" ], "js": [ - "scripts/contentscript.js" + "contentscript.js" ], "run_at": "document_start", "all_frames": true @@ -62,7 +62,7 @@ "https://*.infura.io/" ], "web_accessible_resources": [ - "scripts/inpage.js" + "inpage.js" ], "externally_connectable": { "matches": [ diff --git a/app/notification.html b/app/notification.html index f10cbbf41..457ba7137 100644 --- a/app/notification.html +++ b/app/notification.html @@ -11,6 +11,6 @@ </head> <body class="notification" style="height:600px;"> <div id="app-content"></div> - <script src="./scripts/popup.js" type="text/javascript" charset="utf-8"></script> + <script src="./ui.js" type="text/javascript" charset="utf-8"></script> </body> </html> diff --git a/app/popup.html b/app/popup.html index bf09b97ca..3acfd8c55 100644 --- a/app/popup.html +++ b/app/popup.html @@ -3,10 +3,10 @@ <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1 user-scalable=no"> - <title>MetaMask Plugin</title> + <title>MetaMask</title> </head> <body style="width:357px; height:600px;"> <div id="app-content"></div> - <script src="./scripts/popup.js" type="text/javascript" charset="utf-8"></script> + <script src="./ui.js" type="text/javascript" charset="utf-8"></script> </body> </html> diff --git a/app/scripts/background.js b/app/scripts/background.js index 7bbaa89d6..3ad0a7863 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -19,10 +19,10 @@ const setupRaven = require('./lib/setupRaven') const reportFailedTxToSentry = require('./lib/reportFailedTxToSentry') const setupMetamaskMeshMetrics = require('./lib/setupMetamaskMeshMetrics') const EdgeEncryptor = require('./edge-encryptor') - +const getFirstPreferredLangCode = require('./lib/get-first-preferred-lang-code') const STORAGE_KEY = 'metamask-config' -const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' +const METAMASK_DEBUG = process.env.METAMASK_DEBUG window.log = log log.setDefaultLevel(METAMASK_DEBUG ? 'debug' : 'warn') @@ -58,7 +58,8 @@ setupMetamaskMeshMetrics() async function initialize () { const initState = await loadStateFromPersistence() - await setupController(initState) + const initLangCode = await getFirstPreferredLangCode() + await setupController(initState, initLangCode) log.debug('MetaMask initialization complete.') } @@ -89,7 +90,7 @@ async function loadStateFromPersistence () { return versionedData.data } -function setupController (initState) { +function setupController (initState, initLangCode) { // // MetaMask Controller // @@ -101,6 +102,8 @@ function setupController (initState) { showUnapprovedTx: triggerUi, // initial state initState, + // initial locale code + initLangCode, // platform specific api platform, encryptor: isEdge ? new EdgeEncryptor() : undefined, diff --git a/app/scripts/config.js b/app/scripts/config.js index 74c5b576e..a8470ed82 100644 --- a/app/scripts/config.js +++ b/app/scripts/config.js @@ -13,7 +13,7 @@ const DEFAULT_RPC = 'rinkeby' const OLD_UI_NETWORK_TYPE = 'network' const BETA_UI_NETWORK_TYPE = 'networkBeta' -global.METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' +global.METAMASK_DEBUG = process.env.METAMASK_DEBUG module.exports = { network: { diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js index 7abbc60e7..fe1766273 100644 --- a/app/scripts/contentscript.js +++ b/app/scripts/contentscript.js @@ -7,8 +7,8 @@ const ObjectMultiplex = require('obj-multiplex') const extension = require('extensionizer') const PortStream = require('./lib/port-stream.js') -const inpageContent = fs.readFileSync(path.join(__dirname, '..', '..', 'dist', 'chrome', 'scripts', 'inpage.js')).toString() -const inpageSuffix = '//# sourceURL=' + extension.extension.getURL('scripts/inpage.js') + '\n' +const inpageContent = fs.readFileSync(path.join(__dirname, '..', '..', 'dist', 'chrome', 'inpage.js')).toString() +const inpageSuffix = '//# sourceURL=' + extension.extension.getURL('inpage.js') + '\n' const inpageBundle = inpageContent + inpageSuffix // Eventually this streaming injection could be replaced with: @@ -96,7 +96,7 @@ function logStreamDisconnectWarning (remoteLabel, err) { } function shouldInjectWeb3 () { - return doctypeCheck() && suffixCheck() + return doctypeCheck() && suffixCheck() && documentElementCheck() && !blacklistedDomainCheck() } @@ -131,7 +131,11 @@ function documentElementCheck () { } function blacklistedDomainCheck () { - var blacklistedDomains = ['uscourts.gov', 'dropbox.com'] + var blacklistedDomains = [ + 'uscourts.gov', + 'dropbox.com', + 'webbyawards.com', + ] var currentUrl = window.location.href var currentRegex for (let i = 0; i < blacklistedDomains.length; i++) { diff --git a/app/scripts/controllers/blacklist.js b/app/scripts/controllers/blacklist.js index 33c31dab9..df41c90c0 100644 --- a/app/scripts/controllers/blacklist.js +++ b/app/scripts/controllers/blacklist.js @@ -41,9 +41,9 @@ class BlacklistController { scheduleUpdates () { if (this._phishingUpdateIntervalRef) return - this.updatePhishingList() + this.updatePhishingList().catch(log.warn) this._phishingUpdateIntervalRef = setInterval(() => { - this.updatePhishingList() + this.updatePhishingList().catch(log.warn) }, POLLING_INTERVAL) } @@ -57,4 +57,3 @@ class BlacklistController { } module.exports = BlacklistController - diff --git a/app/scripts/controllers/currency.js b/app/scripts/controllers/currency.js index 25a7a942e..36b8808aa 100644 --- a/app/scripts/controllers/currency.js +++ b/app/scripts/controllers/currency.js @@ -43,20 +43,19 @@ class CurrencyController { this.store.updateState({ conversionDate }) } - updateConversionRate () { - const currentCurrency = this.getCurrentCurrency() - return fetch(`https://api.infura.io/v1/ticker/eth${currentCurrency.toLowerCase()}`) - .then(response => response.json()) - .then((parsedResponse) => { + async updateConversionRate () { + let currentCurrency + try { + currentCurrency = this.getCurrentCurrency() + const response = await fetch(`https://api.infura.io/v1/ticker/eth${currentCurrency.toLowerCase()}`) + const parsedResponse = await response.json() this.setConversionRate(Number(parsedResponse.bid)) this.setConversionDate(Number(parsedResponse.timestamp)) - }).catch((err) => { - if (err) { - console.warn('MetaMask - Failed to query currency conversion.') - this.setConversionRate(0) - this.setConversionDate('N/A') - } - }) + } catch (err) { + log.warn(`MetaMask - Failed to query currency conversion:`, currentCurrency, err) + this.setConversionRate(0) + this.setConversionDate('N/A') + } } scheduleConversionInterval () { diff --git a/app/scripts/controllers/infura.js b/app/scripts/controllers/infura.js index 10adb1004..c6b4c9de2 100644 --- a/app/scripts/controllers/infura.js +++ b/app/scripts/controllers/infura.js @@ -19,15 +19,13 @@ class InfuraController { // Responsible for retrieving the status of Infura's nodes. Can return either // ok, degraded, or down. - checkInfuraNetworkStatus () { - return fetch('https://api.infura.io/v1/status/metamask') - .then(response => response.json()) - .then((parsedResponse) => { - this.store.updateState({ - infuraNetworkStatus: parsedResponse, - }) - return parsedResponse - }) + async checkInfuraNetworkStatus () { + const response = await fetch('https://api.infura.io/v1/status/metamask') + const parsedResponse = await response.json() + this.store.updateState({ + infuraNetworkStatus: parsedResponse, + }) + return parsedResponse } scheduleInfuraNetworkCheck () { @@ -35,7 +33,7 @@ class InfuraController { clearInterval(this.conversionInterval) } this.conversionInterval = setInterval(() => { - this.checkInfuraNetworkStatus() + this.checkInfuraNetworkStatus().catch(log.warn) }, POLLING_INTERVAL) } } diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js index 39d15fd83..b4819d951 100644 --- a/app/scripts/controllers/preferences.js +++ b/app/scripts/controllers/preferences.js @@ -11,6 +11,7 @@ class PreferencesController { tokens: [], useBlockie: false, featureFlags: {}, + currentLocale: opts.initLangCode, }, opts.initState) this.store = new ObservableStore(initState) } @@ -24,6 +25,10 @@ class PreferencesController { return this.store.getState().useBlockie } + setCurrentLocale (key) { + this.store.updateState({ currentLocale: key }) + } + setSelectedAddress (_address) { return new Promise((resolve, reject) => { const address = normalizeAddress(_address) diff --git a/app/scripts/controllers/shapeshift.js b/app/scripts/controllers/shapeshift.js index 3d955c01f..3bbfaa1c5 100644 --- a/app/scripts/controllers/shapeshift.js +++ b/app/scripts/controllers/shapeshift.js @@ -45,18 +45,19 @@ class ShapeshiftController { }) } - updateTx (tx) { - const url = `https://shapeshift.io/txStat/${tx.depositAddress}` - return fetch(url) - .then((response) => { - return response.json() - }).then((json) => { + async updateTx (tx) { + try { + const url = `https://shapeshift.io/txStat/${tx.depositAddress}` + const response = await fetch(url) + const json = await response.json() tx.response = json if (tx.response.status === 'complete') { tx.time = new Date().getTime() } return tx - }) + } catch (err) { + log.warn(err) + } } saveTx (tx) { diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index 3e3909361..31e53554d 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -161,9 +161,11 @@ module.exports = class TransactionController extends EventEmitter { this.emit(`${txMeta.id}:unapproved`, txMeta) } - async newUnapprovedTransaction (txParams) { + async newUnapprovedTransaction (txParams, opts = {}) { log.debug(`MetaMaskController newUnapprovedTransaction ${JSON.stringify(txParams)}`) const initialTxMeta = await this.addUnapprovedTransaction(txParams) + initialTxMeta.origin = opts.origin + this.txStateManager.updateTx(initialTxMeta, '#newUnapprovedTransaction - adding the origin') // listen for tx completion (success, fail) return new Promise((resolve, reject) => { this.txStateManager.once(`${initialTxMeta.id}:finished`, (finishedTxMeta) => { @@ -185,12 +187,12 @@ module.exports = class TransactionController extends EventEmitter { // validate await this.txGasUtil.validateTxParams(txParams) // construct txMeta - const txMeta = this.txStateManager.generateTxMeta({txParams}) + let txMeta = this.txStateManager.generateTxMeta({txParams}) this.addTx(txMeta) this.emit('newUnapprovedTx', txMeta) // add default tx params try { - await this.addTxDefaults(txMeta) + txMeta = await this.addTxDefaults(txMeta) } catch (error) { console.log(error) this.txStateManager.setTxStatusFailed(txMeta.id, error) @@ -213,6 +215,7 @@ module.exports = class TransactionController extends EventEmitter { } txParams.gasPrice = ethUtil.addHexPrefix(gasPrice.toString(16)) txParams.value = txParams.value || '0x0' + if (txParams.to === null) delete txParams.to // set gasLimit return await this.txGasUtil.analyzeGasUsage(txMeta) } @@ -250,7 +253,7 @@ module.exports = class TransactionController extends EventEmitter { // wait for a nonce nonceLock = await this.nonceTracker.getNonceLock(fromAddress) // add nonce to txParams - // if txMeta has lastGasPrice then it is a retry at same nonce with higher + // if txMeta has lastGasPrice then it is a retry at same nonce with higher // gas price transaction and their for the nonce should not be calculated const nonce = txMeta.lastGasPrice ? txMeta.txParams.nonce : nonceLock.nextNonce txMeta.txParams.nonce = ethUtil.addHexPrefix(nonce.toString(16)) @@ -273,12 +276,14 @@ module.exports = class TransactionController extends EventEmitter { async signTransaction (txId) { const txMeta = this.txStateManager.getTx(txId) - const txParams = txMeta.txParams - const fromAddress = txParams.from // add network/chain id - txParams.chainId = ethUtil.addHexPrefix(this.getChainId().toString(16)) + const chainId = this.getChainId() + const txParams = Object.assign({}, txMeta.txParams, { chainId }) + // sign tx + const fromAddress = txParams.from const ethTx = new Transaction(txParams) await this.signEthTx(ethTx, fromAddress) + // set state to signed this.txStateManager.setTxStatusSigned(txMeta.id) const rawTx = ethUtil.bufferToHex(ethTx.serialize()) return rawTx diff --git a/app/scripts/first-time-state.js b/app/scripts/first-time-state.js index 5e8577100..3063df627 100644 --- a/app/scripts/first-time-state.js +++ b/app/scripts/first-time-state.js @@ -1,6 +1,6 @@ // test and development environment variables const env = process.env.METAMASK_ENV -const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' +const METAMASK_DEBUG = process.env.METAMASK_DEBUG // // The default state of MetaMask diff --git a/app/scripts/inpage.js b/app/scripts/inpage.js index 9261e7d64..ec99bfc35 100644 --- a/app/scripts/inpage.js +++ b/app/scripts/inpage.js @@ -9,7 +9,7 @@ const setupDappAutoReload = require('./lib/auto-reload.js') const MetamaskInpageProvider = require('./lib/inpage-provider.js') restoreContextAfterImports() -const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' +const METAMASK_DEBUG = process.env.METAMASK_DEBUG window.log = log log.setDefaultLevel(METAMASK_DEBUG ? 'debug' : 'warn') diff --git a/app/scripts/lib/extractEthjsErrorMessage.js b/app/scripts/lib/extractEthjsErrorMessage.js new file mode 100644 index 000000000..bac541735 --- /dev/null +++ b/app/scripts/lib/extractEthjsErrorMessage.js @@ -0,0 +1,27 @@ +const ethJsRpcSlug = 'Error: [ethjs-rpc] rpc error with payload ' +const errorLabelPrefix = 'Error: ' + +module.exports = extractEthjsErrorMessage + + +// +// ethjs-rpc provides overly verbose error messages +// if we detect this type of message, we extract the important part +// Below is an example input and output +// +// Error: [ethjs-rpc] rpc error with payload {"id":3947817945380,"jsonrpc":"2.0","params":["0xf8eb8208708477359400830398539406012c8cf97bead5deae237070f9587f8e7a266d80b8843d7d3f5a0000000000000000000000000000000000000000000000000000000000081d1a000000000000000000000000000000000000000000000000001ff973cafa800000000000000000000000000000000000000000000000000000038d7ea4c68000000000000000000000000000000000000000000000000000000000000003f48025a04c32a9b630e0d9e7ff361562d850c86b7a884908135956a7e4a336fa0300d19ca06830776423f25218e8d19b267161db526e66895567147015b1f3fc47aef9a3c7"],"method":"eth_sendRawTransaction"} Error: replacement transaction underpriced +// +// Transaction Failed: replacement transaction underpriced +// + + +function extractEthjsErrorMessage(errorMessage) { + const isEthjsRpcError = errorMessage.includes(ethJsRpcSlug) + if (isEthjsRpcError) { + const payloadAndError = errorMessage.slice(ethJsRpcSlug.length) + const originalError = payloadAndError.slice(payloadAndError.indexOf(errorLabelPrefix) + errorLabelPrefix.length) + return originalError + } else { + return errorMessage + } +} diff --git a/app/scripts/lib/get-first-preferred-lang-code.js b/app/scripts/lib/get-first-preferred-lang-code.js new file mode 100644 index 000000000..28612f763 --- /dev/null +++ b/app/scripts/lib/get-first-preferred-lang-code.js @@ -0,0 +1,16 @@ +const extension = require('extensionizer') +const promisify = require('pify') +const allLocales = require('../../_locales/index.json') + +const existingLocaleCodes = allLocales.map(locale => locale.code) + +async function getFirstPreferredLangCode () { + const userPreferredLocaleCodes = await promisify( + extension.i18n.getAcceptLanguages, + { errorFirst: false } + )() + const firstPreferredLangCode = userPreferredLocaleCodes.find(code => existingLocaleCodes.includes(code)) + return firstPreferredLangCode || 'en' +} + +module.exports = getFirstPreferredLangCode diff --git a/app/scripts/lib/nonce-tracker.js b/app/scripts/lib/nonce-tracker.js index ed9dd3f11..5b1cd7f43 100644 --- a/app/scripts/lib/nonce-tracker.js +++ b/app/scripts/lib/nonce-tracker.js @@ -31,14 +31,13 @@ class NonceTracker { const networkNonceResult = await this._getNetworkNextNonce(address) const highestLocallyConfirmed = this._getHighestLocallyConfirmed(address) const nextNetworkNonce = networkNonceResult.nonce - const highestLocalNonce = highestLocallyConfirmed - const highestSuggested = Math.max(nextNetworkNonce, highestLocalNonce) + const highestSuggested = Math.max(nextNetworkNonce, highestLocallyConfirmed) const pendingTxs = this.getPendingTransactions(address) const localNonceResult = this._getHighestContinuousFrom(pendingTxs, highestSuggested) || 0 nonceDetails.params = { - highestLocalNonce, + highestLocallyConfirmed, highestSuggested, nextNetworkNonce, } diff --git a/app/scripts/lib/reportFailedTxToSentry.js b/app/scripts/lib/reportFailedTxToSentry.js index ee73f6845..e09f4f1f8 100644 --- a/app/scripts/lib/reportFailedTxToSentry.js +++ b/app/scripts/lib/reportFailedTxToSentry.js @@ -1,5 +1,4 @@ -const ethJsRpcSlug = 'Error: [ethjs-rpc] rpc error with payload ' -const errorLabelPrefix = 'Error: ' +const extractEthjsErrorMessage = require('./extractEthjsErrorMessage') module.exports = reportFailedTxToSentry @@ -9,30 +8,9 @@ module.exports = reportFailedTxToSentry // function reportFailedTxToSentry({ raven, txMeta }) { - const errorMessage = extractErrorMessage(txMeta.err.message) + const errorMessage = 'Transaction Failed: ' + extractEthjsErrorMessage(txMeta.err.message) raven.captureMessage(errorMessage, { // "extra" key is required by Sentry extra: txMeta, }) } - -// -// ethjs-rpc provides overly verbose error messages -// if we detect this type of message, we extract the important part -// Below is an example input and output -// -// Error: [ethjs-rpc] rpc error with payload {"id":3947817945380,"jsonrpc":"2.0","params":["0xf8eb8208708477359400830398539406012c8cf97bead5deae237070f9587f8e7a266d80b8843d7d3f5a0000000000000000000000000000000000000000000000000000000000081d1a000000000000000000000000000000000000000000000000001ff973cafa800000000000000000000000000000000000000000000000000000038d7ea4c68000000000000000000000000000000000000000000000000000000000000003f48025a04c32a9b630e0d9e7ff361562d850c86b7a884908135956a7e4a336fa0300d19ca06830776423f25218e8d19b267161db526e66895567147015b1f3fc47aef9a3c7"],"method":"eth_sendRawTransaction"} Error: replacement transaction underpriced -// -// Transaction Failed: replacement transaction underpriced -// - -function extractErrorMessage(errorMessage) { - const isEthjsRpcError = errorMessage.includes(ethJsRpcSlug) - if (isEthjsRpcError) { - const payloadAndError = errorMessage.slice(ethJsRpcSlug.length) - const originalError = payloadAndError.slice(payloadAndError.indexOf(errorLabelPrefix) + errorLabelPrefix.length) - return `Transaction Failed: ${originalError}` - } else { - return `Transaction Failed: ${errorMessage}` - } -} diff --git a/app/scripts/lib/setupRaven.js b/app/scripts/lib/setupRaven.js index 02c01b755..9ec9a256f 100644 --- a/app/scripts/lib/setupRaven.js +++ b/app/scripts/lib/setupRaven.js @@ -1,5 +1,6 @@ const Raven = require('raven-js') -const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' +const METAMASK_DEBUG = process.env.METAMASK_DEBUG +const extractEthjsErrorMessage = require('./extractEthjsErrorMessage') const PROD = 'https://3567c198f8a8412082d32655da2961d0@sentry.io/273505' const DEV = 'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496' @@ -21,8 +22,22 @@ function setupRaven(opts) { const client = Raven.config(ravenTarget, { release, transport: function(opts) { - // modify report urls const report = opts.data + // simplify certain complex error messages + report.exception.values.forEach(item => { + let errorMessage = item.value + // simplify ethjs error messages + errorMessage = extractEthjsErrorMessage(errorMessage) + // simplify 'Transaction Failed: known transaction' + if (errorMessage.indexOf('Transaction Failed: known transaction') === 0) { + // cut the hash from the error message + errorMessage = 'Transaction Failed: known transaction' + } + // finalize + item.value = errorMessage + }) + + // modify report urls rewriteReportUrls(report) // make request normally client._makeRequest(opts) diff --git a/app/scripts/lib/tx-gas-utils.js b/app/scripts/lib/tx-gas-utils.js index 0fa9dd8d4..829b4c421 100644 --- a/app/scripts/lib/tx-gas-utils.js +++ b/app/scripts/lib/tx-gas-utils.js @@ -52,7 +52,9 @@ module.exports = class TxGasUtil { // if recipient has no code, gas is 21k max: const recipient = txParams.to const hasRecipient = Boolean(recipient) - const code = await this.query.getCode(recipient) + let code + if (recipient) code = await this.query.getCode(recipient) + if (hasRecipient && (!code || code === '0x')) { txParams.gas = SIMPLE_GAS_COST txMeta.simpleSend = true // Prevents buffer addition @@ -100,6 +102,7 @@ module.exports = class TxGasUtil { } async validateTxParams (txParams) { + this.validateFrom(txParams) this.validateRecipient(txParams) if ('value' in txParams) { const value = txParams.value.toString() @@ -112,6 +115,12 @@ module.exports = class TxGasUtil { } } } + + validateFrom (txParams) { + if ( !(typeof txParams.from === 'string') ) throw new Error(`Invalid from address ${txParams.from} not a string`) + if (!isValidAddress(txParams.from)) throw new Error('Invalid from address') + } + validateRecipient (txParams) { if (txParams.to === '0x' || txParams.to === null ) { if (txParams.data) { @@ -124,4 +133,4 @@ module.exports = class TxGasUtil { } return txParams } -} +}
\ No newline at end of file diff --git a/app/scripts/lib/tx-state-manager.js b/app/scripts/lib/tx-state-manager.js index ad07c813f..2ab24d6a0 100644 --- a/app/scripts/lib/tx-state-manager.js +++ b/app/scripts/lib/tx-state-manager.js @@ -38,11 +38,6 @@ module.exports = class TransactionStateManager extends EventEmitter { }, opts) } - // Returns the number of txs for the current network. - getTxCount () { - return this.getTxList().length - } - getTxList () { const network = this.getNetwork() const fullTxList = this.getFullTxList() @@ -88,7 +83,7 @@ module.exports = class TransactionStateManager extends EventEmitter { txMeta.history.push(snapshot) const transactions = this.getFullTxList() - const txCount = this.getTxCount() + const txCount = transactions.length const txHistoryLimit = this.txHistoryLimit // checks if the length of the tx history is @@ -111,12 +106,9 @@ module.exports = class TransactionStateManager extends EventEmitter { } updateTx (txMeta, note) { + // validate txParams if (txMeta.txParams) { - Object.keys(txMeta.txParams).forEach((key) => { - const value = txMeta.txParams[key] - if (typeof value !== 'string') console.error(`${key}: ${value} in txParams is not a string`) - if (!ethUtil.isHexPrefixed(value)) console.error('is not hex prefixed, anything on txParams must be hex prefixed') - }) + this.validateTxParams(txMeta.txParams) } // create txMeta snapshot for history @@ -144,6 +136,23 @@ module.exports = class TransactionStateManager extends EventEmitter { this.updateTx(txMeta, `txStateManager#updateTxParams`) } + // validates txParams members by type + validateTxParams(txParams) { + Object.keys(txParams).forEach((key) => { + const value = txParams[key] + // validate types + switch (key) { + case 'chainId': + if (typeof value !== 'number' && typeof value !== 'string') throw new Error(`${key} in txParams is not a Number or hex string. got: (${value})`) + break + default: + if (typeof value !== 'string') throw new Error(`${key} in txParams is not a string. got: (${value})`) + if (!ethUtil.isHexPrefixed(value)) throw new Error(`${key} in txParams is not hex prefixed. got: (${value})`) + break + } + }) + } + /* Takes an object of fields to search for eg: let thingsToLookFor = { diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 18d71874a..b96acc9da 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -49,7 +49,7 @@ module.exports = class MetamaskController extends EventEmitter { /** * @constructor - * @param {Object} opts + * @param {Object} opts */ constructor (opts) { super() @@ -57,7 +57,6 @@ module.exports = class MetamaskController extends EventEmitter { this.defaultMaxListeners = 20 this.sendUpdate = debounce(this.privateSendUpdate.bind(this), 200) - this.opts = opts const initState = opts.initState || {} this.recordFirstTimeInfo(initState) @@ -82,6 +81,7 @@ module.exports = class MetamaskController extends EventEmitter { // preferences controller this.preferencesController = new PreferencesController({ initState: initState.PreferencesController, + initLangCode: opts.initLangCode, }) // currency controller @@ -241,6 +241,11 @@ module.exports = class MetamaskController extends EventEmitter { static: { eth_syncing: false, web3_clientVersion: `MetaMask/v${version}`, + eth_sendTransaction: (payload, next, end) => { + const origin = payload.origin + const txParams = payload.params[0] + nodeify(this.txController.newUnapprovedTransaction, this.txController)(txParams, { origin }, end) + }, }, // account mgmt getAccounts: (cb) => { @@ -255,7 +260,6 @@ module.exports = class MetamaskController extends EventEmitter { cb(null, result) }, // tx signing - processTransaction: nodeify(async (txParams) => await this.txController.newUnapprovedTransaction(txParams), this), // old style msg signing processMessage: this.newUnsignedMessage.bind(this), // personal_sign msg signing @@ -296,8 +300,8 @@ module.exports = class MetamaskController extends EventEmitter { /** * The metamask-state of the various controllers, made available to the UI - * - * @returns {Object} status + * + * @returns {Object} status */ getState () { const wallet = this.configManager.getWallet() @@ -335,8 +339,8 @@ module.exports = class MetamaskController extends EventEmitter { /** * Returns an api-object which is consumed by the UI - * - * @returns {Object} + * + * @returns {Object} */ getApi () { const keyringController = this.keyringController @@ -351,6 +355,7 @@ module.exports = class MetamaskController extends EventEmitter { getState: (cb) => cb(null, this.getState()), setCurrentCurrency: this.setCurrentCurrency.bind(this), setUseBlockie: this.setUseBlockie.bind(this), + setCurrentLocale: this.setCurrentLocale.bind(this), markAccountsFound: this.markAccountsFound.bind(this), markPasswordForgotten: this.markPasswordForgotten.bind(this), unMarkPasswordForgotten: this.unMarkPasswordForgotten.bind(this), @@ -365,7 +370,7 @@ module.exports = class MetamaskController extends EventEmitter { placeSeedWords: this.placeSeedWords.bind(this), verifySeedPhrase: nodeify(this.verifySeedPhrase, this), clearSeedWordCache: this.clearSeedWordCache.bind(this), - resetAccount: this.resetAccount.bind(this), + resetAccount: nodeify(this.resetAccount, this), importAccountWithStrategy: this.importAccountWithStrategy.bind(this), // vault management @@ -426,14 +431,14 @@ module.exports = class MetamaskController extends EventEmitter { /** * Creates a new Vault(?) and create a new keychain(?) - * + * * A vault is ... - * + * * A keychain is ... - * + * * * @param {} password - * + * * @returns {} vault */ async createNewVaultAndKeychain (password) { @@ -479,9 +484,9 @@ module.exports = class MetamaskController extends EventEmitter { /** * Retrieves the first Identiy from the passed Vault and selects the related address - * + * * An Identity is ... - * + * * @param {} vault */ selectFirstIdentity (vault) { @@ -495,8 +500,8 @@ module.exports = class MetamaskController extends EventEmitter { // /** - * Adds a new account to ... - * + * Adds a new account to ... + * * @returns {} keyState */ async addNewAccount () { @@ -522,10 +527,10 @@ module.exports = class MetamaskController extends EventEmitter { /** * Adds the current vault's seed words to the UI's state tree. - * + * * Used when creating a first vault, to allow confirmation. * Also used when revealing the seed words in the confirmation view. - */ + */ placeSeedWords (cb) { this.verifySeedPhrase() @@ -540,7 +545,7 @@ module.exports = class MetamaskController extends EventEmitter { /** * Verifies the validity of the current vault's seed phrase. - * + * * Validity: seed phrase restores the accounts belonging to the current vault. * * Called when the first account is created and on unlocking the vault. @@ -571,27 +576,32 @@ module.exports = class MetamaskController extends EventEmitter { /** * Remove the primary account seed phrase from the UI's state tree. - * + * * The seed phrase remains available in the background process. - * + * */ clearSeedWordCache (cb) { this.configManager.setSeedWords(null) cb(null, this.preferencesController.getSelectedAddress()) } - + /** * ? */ - resetAccount (cb) { + async resetAccount (cb) { const selectedAddress = this.preferencesController.getSelectedAddress() this.txController.wipeTransactions(selectedAddress) - cb(null, selectedAddress) + + const networkController = this.networkController + const oldType = networkController.getProviderConfig().type + await networkController.setProviderType(oldType, true) + + return selectedAddress } /** * Imports an account ... ? - * + * * @param {} strategy * @param {} args * @param {} cb @@ -634,9 +644,9 @@ module.exports = class MetamaskController extends EventEmitter { } // Prefixed Style Message Signing Methods: - + /** - * + * * @param {} msgParams * @param {} cb */ @@ -655,7 +665,7 @@ module.exports = class MetamaskController extends EventEmitter { } }) } - + /** * @param {} msgParams */ @@ -676,7 +686,7 @@ module.exports = class MetamaskController extends EventEmitter { return this.getState() }) } - + /** * @param {} msgParams */ @@ -697,13 +707,13 @@ module.exports = class MetamaskController extends EventEmitter { return this.getState() }) } - + // --------------------------------------------------------------------------- // Account Restauration /** * ? - * + * * @param {} migratorOutput */ restoreOldVaultAccounts (migratorOutput) { @@ -714,7 +724,7 @@ module.exports = class MetamaskController extends EventEmitter { /** * ? - * + * * @param {} migratorOutput */ restoreOldLostAccounts (migratorOutput) { @@ -728,9 +738,9 @@ module.exports = class MetamaskController extends EventEmitter { /** * Import (lost) Accounts - * + * * @param {Object} {lostAccounts} @Array accounts <{ address, privateKey }> - * + * * Uses the array's private keys to create a new Simple Key Pair keychain * and add it to the keyring controller. */ @@ -823,7 +833,7 @@ module.exports = class MetamaskController extends EventEmitter { if (cb && typeof cb === 'function') { cb(null, this.getState()) } - } + } cancelPersonalMessage (msgId, cb) { const messageManager = this.personalMessageManager @@ -978,7 +988,7 @@ module.exports = class MetamaskController extends EventEmitter { const percentileNum = percentile(50, lowestPrices) const percentileNumBn = new BN(percentileNum) return '0x' + percentileNumBn.mul(GWEI_BN).toString(16) - } + } //============================================================================= // CONFIG @@ -1029,6 +1039,15 @@ module.exports = class MetamaskController extends EventEmitter { } } + setCurrentLocale (key, cb) { + try { + this.preferencesController.setCurrentLocale(key) + cb(null) + } catch (err) { + cb(err) + } + } + recordFirstTimeInfo (initState) { if (!('firstTimeInfo' in initState)) { initState.firstTimeInfo = { diff --git a/app/scripts/migrations/023.js b/app/scripts/migrations/023.js new file mode 100644 index 000000000..bce0a5bea --- /dev/null +++ b/app/scripts/migrations/023.js @@ -0,0 +1,50 @@ + +const version = 23 + +/* + +This migration removes transactions that are no longer usefull down to 40 total + +*/ + +const clone = require('clone') + +module.exports = { + version, + + migrate: function (originalVersionedData) { + const versionedData = clone(originalVersionedData) + versionedData.meta.version = version + try { + const state = versionedData.data + const newState = transformState(state) + versionedData.data = newState + } catch (err) { + console.warn(`MetaMask Migration #${version}` + err.stack) + } + return Promise.resolve(versionedData) + }, +} + +function transformState (state) { + const newState = state + const transactions = newState.TransactionController.transactions + + if (transactions.length <= 40) return newState + + let reverseTxList = transactions.reverse() + let stripping = true + while (reverseTxList.length > 40 && stripping) { + let txIndex = reverseTxList.findIndex((txMeta) => { + return (txMeta.status === 'failed' || + txMeta.status === 'rejected' || + txMeta.status === 'confirmed' || + txMeta.status === 'dropped') + }) + if (txIndex < 0) stripping = false + else reverseTxList.splice(txIndex, 1) + } + + newState.TransactionController.transactions = reverseTxList.reverse() + return newState +} diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js index b49a40c65..811e06b6b 100644 --- a/app/scripts/migrations/index.js +++ b/app/scripts/migrations/index.js @@ -33,4 +33,5 @@ module.exports = [ require('./020'), require('./021'), require('./022'), + require('./023'), ] diff --git a/app/scripts/popup.js b/app/scripts/popup.js deleted file mode 100644 index e78981f06..000000000 --- a/app/scripts/popup.js +++ /dev/null @@ -1,78 +0,0 @@ -const injectCss = require('inject-css') -const OldMetaMaskUiCss = require('../../old-ui/css') -const NewMetaMaskUiCss = require('../../ui/css') -const startPopup = require('./popup-core') -const PortStream = require('./lib/port-stream.js') -const isPopupOrNotification = require('./lib/is-popup-or-notification') -const extension = require('extensionizer') -const ExtensionPlatform = require('./platforms/extension') -const NotificationManager = require('./lib/notification-manager') -const notificationManager = new NotificationManager() -const setupRaven = require('./lib/setupRaven') - -// create platform global -global.platform = new ExtensionPlatform() - -// setup sentry error reporting -const release = global.platform.getVersion() -setupRaven({ release }) - -// inject css -// const css = MetaMaskUiCss() -// injectCss(css) - -// identify window type (popup, notification) -const windowType = isPopupOrNotification() -global.METAMASK_UI_TYPE = windowType -closePopupIfOpen(windowType) - -// setup stream to background -const extensionPort = extension.runtime.connect({ name: windowType }) -const connectionStream = new PortStream(extensionPort) - -// start ui -const container = document.getElementById('app-content') -startPopup({ container, connectionStream }, (err, store) => { - if (err) return displayCriticalError(err) - - // Code commented out until we begin auto adding users to NewUI - // const { isMascara, identities = {}, featureFlags = {} } = store.getState().metamask - // const firstTime = Object.keys(identities).length === 0 - const { isMascara, featureFlags = {} } = store.getState().metamask - let betaUIState = featureFlags.betaUI - - // Code commented out until we begin auto adding users to NewUI - // const useBetaCss = isMascara || firstTime || betaUIState - const useBetaCss = isMascara || betaUIState - - let css = useBetaCss ? NewMetaMaskUiCss() : OldMetaMaskUiCss() - let deleteInjectedCss = injectCss(css) - let newBetaUIState - - store.subscribe(() => { - const state = store.getState() - newBetaUIState = state.metamask.featureFlags.betaUI - if (newBetaUIState !== betaUIState) { - deleteInjectedCss() - betaUIState = newBetaUIState - css = betaUIState ? NewMetaMaskUiCss() : OldMetaMaskUiCss() - deleteInjectedCss = injectCss(css) - } - if (state.appState.shouldClose) notificationManager.closePopup() - }) -}) - - -function closePopupIfOpen (windowType) { - if (windowType !== 'notification') { - // should close only chrome popup - notificationManager.closePopup() - } -} - -function displayCriticalError (err) { - container.innerHTML = '<div class="critical-error">The MetaMask app failed to load: please open and close MetaMask again to restart.</div>' - container.style.height = '80px' - log.error(err.stack) - throw err -} diff --git a/app/scripts/ui.js b/app/scripts/ui.js new file mode 100644 index 000000000..13c7ac5ec --- /dev/null +++ b/app/scripts/ui.js @@ -0,0 +1,84 @@ +const injectCss = require('inject-css') +const OldMetaMaskUiCss = require('../../old-ui/css') +const NewMetaMaskUiCss = require('../../ui/css') +const startPopup = require('./popup-core') +const PortStream = require('./lib/port-stream.js') +const isPopupOrNotification = require('./lib/is-popup-or-notification') +const extension = require('extensionizer') +const ExtensionPlatform = require('./platforms/extension') +const NotificationManager = require('./lib/notification-manager') +const notificationManager = new NotificationManager() +const setupRaven = require('./lib/setupRaven') + +start().catch(log.error) + +async function start() { + + // create platform global + global.platform = new ExtensionPlatform() + + // setup sentry error reporting + const release = global.platform.getVersion() + setupRaven({ release }) + + // inject css + // const css = MetaMaskUiCss() + // injectCss(css) + + // identify window type (popup, notification) + const windowType = isPopupOrNotification() + global.METAMASK_UI_TYPE = windowType + closePopupIfOpen(windowType) + + // setup stream to background + const extensionPort = extension.runtime.connect({ name: windowType }) + const connectionStream = new PortStream(extensionPort) + + // start ui + const container = document.getElementById('app-content') + startPopup({ container, connectionStream }, (err, store) => { + if (err) return displayCriticalError(err) + + // Code commented out until we begin auto adding users to NewUI + // const { isMascara, identities = {}, featureFlags = {} } = store.getState().metamask + // const firstTime = Object.keys(identities).length === 0 + const { isMascara, featureFlags = {} } = store.getState().metamask + let betaUIState = featureFlags.betaUI + + // Code commented out until we begin auto adding users to NewUI + // const useBetaCss = isMascara || firstTime || betaUIState + const useBetaCss = isMascara || betaUIState + + let css = useBetaCss ? NewMetaMaskUiCss() : OldMetaMaskUiCss() + let deleteInjectedCss = injectCss(css) + let newBetaUIState + + store.subscribe(() => { + const state = store.getState() + newBetaUIState = state.metamask.featureFlags.betaUI + if (newBetaUIState !== betaUIState) { + deleteInjectedCss() + betaUIState = newBetaUIState + css = betaUIState ? NewMetaMaskUiCss() : OldMetaMaskUiCss() + deleteInjectedCss = injectCss(css) + } + if (state.appState.shouldClose) notificationManager.closePopup() + }) + }) + + + function closePopupIfOpen (windowType) { + if (windowType !== 'notification') { + // should close only chrome popup + notificationManager.closePopup() + } + } + + function displayCriticalError (err) { + container.innerHTML = '<div class="critical-error">The MetaMask app failed to load: please open and close MetaMask again to restart.</div>' + container.style.height = '80px' + log.error(err.stack) + throw err + } + +} diff --git a/development/genStates.js b/development/genStates.js index bc274c757..0ac1059be 100644 --- a/development/genStates.js +++ b/development/genStates.js @@ -1,6 +1,8 @@ const fs = require('fs') const path = require('path') const promisify = require('pify') +const enLocaleMessages = require('../app/_locales/en/messages.json') + start().catch(console.error) @@ -12,6 +14,9 @@ async function start () { const stateFilePath = path.join(__dirname, 'states', stateFileName) const stateFileContent = await promisify(fs.readFile)(stateFilePath, 'utf8') const state = JSON.parse(stateFileContent) + + state.localeMessages = { en: enLocaleMessages, current: {} } + const stateName = stateFileName.split('.')[0].replace(/-/g, ' ', 'g') states[stateName] = state })) diff --git a/development/metamaskbot-build-announce.js b/development/metamaskbot-build-announce.js new file mode 100755 index 000000000..88614ca5c --- /dev/null +++ b/development/metamaskbot-build-announce.js @@ -0,0 +1,62 @@ +#!/usr/bin/env node +const request = require('request-promise') +const VERSION = require('../dist/chrome/manifest.json').version + +start().catch(console.error) + +async function start() { + + const GITHUB_COMMENT_TOKEN = process.env.GITHUB_COMMENT_TOKEN + const CIRCLE_PULL_REQUEST = process.env.CIRCLE_PULL_REQUEST + console.log('CIRCLE_PULL_REQUEST', CIRCLE_PULL_REQUEST) + const CIRCLE_SHA1 = process.env.CIRCLE_SHA1 + console.log('CIRCLE_SHA1', CIRCLE_SHA1) + const CIRCLE_BUILD_NUM = process.env.CIRCLE_BUILD_NUM + console.log('CIRCLE_BUILD_NUM', CIRCLE_BUILD_NUM) + + if (!CIRCLE_PULL_REQUEST) { + console.warn(`No pull request detected for commit "${CIRCLE_SHA1}"`) + return + } + + const CIRCLE_PR_NUMBER = CIRCLE_PULL_REQUEST.split('/').pop() + const SHORT_SHA1 = CIRCLE_SHA1.slice(0,7) + const BUILD_LINK_BASE = `https://${CIRCLE_BUILD_NUM}-42009758-gh.circle-artifacts.com/0` + + const MASCARA = `${BUILD_LINK_BASE}/builds/mascara/home.html` + const CHROME = `${BUILD_LINK_BASE}/builds/metamask-chrome-${VERSION}.zip` + const FIREFOX = `${BUILD_LINK_BASE}/builds/metamask-firefox-${VERSION}.zip` + const EDGE = `${BUILD_LINK_BASE}/builds/metamask-edge-${VERSION}.zip` + const OPERA = `${BUILD_LINK_BASE}/builds/metamask-opera-${VERSION}.zip` + const WALKTHROUGH = `${BUILD_LINK_BASE}/test-artifacts/screens/walkthrough%20%28en%29.gif` + + const commentBody = ` + <details> + <summary> + Builds ready [${SHORT_SHA1}]: + <a href="${MASCARA}">mascara</a>, + <a href="${CHROME}">chrome</a>, + <a href="${FIREFOX}">firefox</a>, + <a href="${EDGE}">edge</a>, + <a href="${OPERA}">opera</a> + </summary> + <image src="${WALKTHROUGH}"> + </details> + ` + + const JSON_PAYLOAD = JSON.stringify({ body: commentBody }) + const POST_COMMENT_URI = `https://api.github.com/repos/metamask/metamask-extension/issues/${CIRCLE_PR_NUMBER}/comments` + console.log(`Announcement:\n${commentBody}`) + console.log(`Posting to: ${POST_COMMENT_URI}`) + + await request({ + method: 'POST', + uri: POST_COMMENT_URI, + body: JSON_PAYLOAD, + headers: { + 'User-Agent': 'metamaskbot', + 'Authorization': `token ${GITHUB_COMMENT_TOKEN}`, + }, + }) + +} diff --git a/development/sentry-publish.js b/development/sentry-publish.js new file mode 100644 index 000000000..ab3acabbd --- /dev/null +++ b/development/sentry-publish.js @@ -0,0 +1,55 @@ +#!/usr/bin/env node +const pify = require('pify') +const exec = pify(require('child_process').exec, { multiArgs: true }) +const VERSION = require('../dist/chrome/manifest.json').version + +start().catch(console.error) + +async function start(){ + const authWorked = await checkIfAuthWorks() + if (!authWorked) { + console.log(`Sentry auth failed...`) + } + // check if version exists or not + const versionAlreadyExists = await checkIfVersionExists() + // abort if versions exists + if (versionAlreadyExists) { + console.log(`Version "${VERSION}" already exists on Sentry, aborting sourcemap upload.`) + return + } + + // create sentry release + console.log(`creating Sentry release for "${VERSION}"...`) + await exec(`sentry-cli releases --org 'metamask' --project 'metamask' new ${VERSION}`) + console.log(`removing any existing files from Sentry release "${VERSION}"...`) + await exec(`sentry-cli releases --org 'metamask' --project 'metamask' files ${VERSION} delete --all`) + // upload sentry source and sourcemaps + console.log(`uploading source files Sentry release "${VERSION}"...`) + await exec(`for FILEPATH in ./dist/chrome/*.js; do [ -e $FILEPATH ] || continue; export FILE=\`basename $FILEPATH\` && echo uploading $FILE && sentry-cli releases --org 'metamask' --project 'metamask' files ${VERSION} upload $FILEPATH metamask/$FILE; done;`) + console.log(`uploading sourcemaps Sentry release "${VERSION}"...`) + await exec(`sentry-cli releases --org 'metamask' --project 'metamask' files ${VERSION} upload-sourcemaps ./dist/sourcemaps/ --url-prefix 'sourcemaps'`) + console.log('all done!') +} + +async function checkIfAuthWorks() { + const itWorked = await doesNotFail(async () => { + await exec(`sentry-cli releases --org 'metamask' --project 'metamask' list`) + }) + return itWorked +} + +async function checkIfVersionExists() { + const versionAlreadyExists = await doesNotFail(async () => { + await exec(`sentry-cli releases --org 'metamask' --project 'metamask' info ${VERSION}`) + }) + return versionAlreadyExists +} + +async function doesNotFail(asyncFn) { + try { + await asyncFn() + return true + } catch (err) { + return false + } +} diff --git a/development/states/add-token.json b/development/states/add-token.json index e78393b7f..9c0f16372 100644 --- a/development/states/add-token.json +++ b/development/states/add-token.json @@ -106,7 +106,8 @@ "errors": {}, "maxModeOn": false, "editingTransactionId": null - } + }, + "currentLocale": "en" }, "appState": { "menuOpen": false, diff --git a/development/states/confirm-new-ui.json b/development/states/confirm-new-ui.json index 6981781a9..ae3098ecb 100644 --- a/development/states/confirm-new-ui.json +++ b/development/states/confirm-new-ui.json @@ -128,7 +128,8 @@ "errors": {}, "maxModeOn": false, "editingTransactionId": null - } + }, + "currentLocale": "en" }, "appState": { "menuOpen": false, diff --git a/development/states/confirm-sig-requests.json b/development/states/confirm-sig-requests.json index 0a691e948..b51003d11 100644 --- a/development/states/confirm-sig-requests.json +++ b/development/states/confirm-sig-requests.json @@ -149,7 +149,8 @@ "errors": {}, "maxModeOn": false, "editingTransactionId": null - } + }, + "currentLocale": "en" }, "appState": { "menuOpen": false, diff --git a/development/states/first-time.json b/development/states/first-time.json index 4f5352992..fe9188b80 100644 --- a/development/states/first-time.json +++ b/development/states/first-time.json @@ -36,7 +36,8 @@ }, "shapeShiftTxList": [], "lostAccounts": [], - "tokens": [] + "tokens": [], + "currentLocale": "en" }, "appState": { "menuOpen": false, diff --git a/development/states/send-edit.json b/development/states/send-edit.json index 6981781a9..ae3098ecb 100644 --- a/development/states/send-edit.json +++ b/development/states/send-edit.json @@ -128,7 +128,8 @@ "errors": {}, "maxModeOn": false, "editingTransactionId": null - } + }, + "currentLocale": "en" }, "appState": { "menuOpen": false, diff --git a/development/states/send-new-ui.json b/development/states/send-new-ui.json index a0a2c66e4..1297a9139 100644 --- a/development/states/send-new-ui.json +++ b/development/states/send-new-ui.json @@ -107,7 +107,8 @@ "errors": {}, "maxModeOn": false, "editingTransactionId": null - } + }, + "currentLocale": "en" }, "appState": { "menuOpen": false, diff --git a/development/states/tx-list-items.js b/development/states/tx-list-items.js new file mode 100644 index 000000000..d567e3fed --- /dev/null +++ b/development/states/tx-list-items.js @@ -0,0 +1,128 @@ +{ + "metamask": { + "isInitialized": true, + "isUnlocked": true, + "featureFlags": {"betaUI": true}, + "rpcTarget": "https://rawtestrpc.metamask.io/", + "identities": { + "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": { + "address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", + "name": "Send Account 1" + }, + "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": { + "address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb", + "name": "Send Account 2" + }, + "0x2f8d4a878cfa04a6e60d46362f5644deab66572d": { + "address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d", + "name": "Send Account 3" + }, + "0xd85a4b6a394794842887b8284293d69163007bbb": { + "address": "0xd85a4b6a394794842887b8284293d69163007bbb", + "name": "Send Account 4" + } + }, + "currentCurrency": "USD", + "conversionRate": 1200.88200327, + "conversionDate": 1489013762, + "noActiveNotices": true, + "frequentRpcList": [], + "network": "1", + "accounts": { + "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": { + "code": "0x", + "balance": "0x47c9d71831c76efe", + "nonce": "0x1b", + "address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825" + }, + "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": { + "code": "0x", + "balance": "0x37452b1315889f80", + "nonce": "0xa", + "address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb" + }, + "0x2f8d4a878cfa04a6e60d46362f5644deab66572d": { + "code": "0x", + "balance": "0x30c9d71831c76efe", + "nonce": "0x1c", + "address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d" + }, + "0xd85a4b6a394794842887b8284293d69163007bbb": { + "code": "0x", + "balance": "0x0", + "nonce": "0x0", + "address": "0xd85a4b6a394794842887b8284293d69163007bbb" + } + }, + "addressBook": [ + { + "address": "0x06195827297c7a80a443b6894d3bdb8824b43896", + "name": "Address Book Account 1" + } + ], + "tokens": [], + "transactions": {}, + "selectedAddressTxList": [ + {"err":{"message":"Error: [ethjs-rpc] rpc error with payload {\"id\":8726092611900,\"jsonrpc\":\"2.0\",\"params\":[\"0xf8610384773594008094f45d68f31b3c9ac84ff0d07b86c59b753a60b1e3808029a052e5246c9a404f756a246b8cec545099741aeb4e6e0add935a5b7a366fa88f95a0538eaa2421e50377c534244dcdcd15ace00bf9c0adbd9eb162baae2b9e89a36f\"],\"method\":\"eth_sendRawTransaction\"} Error: intrinsic gas too low","stack":"Error: [ethjs-rpc] rpc error with payload {\"id\":8726092611900,\"jsonrpc\":\"2.0\",\"params\":[\"0xf8610384773594008094f45d68f31b3c9ac84ff0d07b86c59b753a60b1e3808029a052e5246c9a404f756a246b8cec545099741aeb4e6e0add935a5b7a366fa88f95a0538eaa2421e50377c534244dcdcd15ace00bf9c0adbd9eb162baae2b9e89a36f\"],\"method\":\"eth_sendRawTransaction\"} Error: intrinsic gas too low\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:72360:28\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103521:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27180:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27024:25)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:106691:25\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103501:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27033:9\n at eachLimit (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:26723:36)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:26937:16\n at end (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103498:5)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:106913:40"},"estimatedGas":"0xcf08","gasLimitSpecified":true,"gasPriceSpecified":true,"history":[{"id":4068311466147836,"loadingDefaults":true,"metamaskNetworkId":"1","status":"unapproved","time":1522378334455,"txParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","gas":"0xcf08","gasPrice":"0x77359400","to":"0xf45d68f31b3c9ac84ff0d07b86c59b753a60b1e3","value":"0x0"}},[{"op":"replace","path":"/loadingDefaults","value":false},{"op":"add","path":"/gasPriceSpecified","value":true},{"op":"add","path":"/gasLimitSpecified","value":true},{"op":"add","path":"/estimatedGas","value":"0xcf08"}],[{"note":"confTx: user approved transaction","op":"replace","path":"/txParams/gas","value":"0x0"}],[{"note":"txStateManager: setting status to approved","op":"replace","path":"/status","value":"approved"}],[{"note":"transactions#approveTransaction","op":"add","path":"/txParams/nonce","value":"0x3"},{"op":"add","path":"/nonceDetails","value":{"local":{"details":{"highest":3,"startPoint":3},"name":"local","nonce":3},"network":{"details":{"baseCount":3},"name":"network","nonce":3},"params":{"highestLocalNonce":3,"highestSuggested":3,"nextNetworkNonce":3}}}],[{"note":"txStateManager: setting status to signed","op":"add","path":"/txParams/chainId","value":"0x3"},{"op":"replace","path":"/status","value":"signed"}],[{"note":"transactions#publishTransaction","op":"add","path":"/rawTx","value":"0xf8610384773594008094f45d68f31b3c9ac84ff0d07b86c59b753a60b1e3808029a052e5246c9a404f756a246b8cec545099741aeb4e6e0add935a5b7a366fa88f95a0538eaa2421e50377c534244dcdcd15ace00bf9c0adbd9eb162baae2b9e89a36f"}],[{"op":"add","path":"/err","value":{"message":"Error: [ethjs-rpc] rpc error with payload {\"id\":8726092611900,\"jsonrpc\":\"2.0\",\"params\":[\"0xf8610384773594008094f45d68f31b3c9ac84ff0d07b86c59b753a60b1e3808029a052e5246c9a404f756a246b8cec545099741aeb4e6e0add935a5b7a366fa88f95a0538eaa2421e50377c534244dcdcd15ace00bf9c0adbd9eb162baae2b9e89a36f\"],\"method\":\"eth_sendRawTransaction\"} Error: intrinsic gas too low","stack":"Error: [ethjs-rpc] rpc error with payload {\"id\":8726092611900,\"jsonrpc\":\"2.0\",\"params\":[\"0xf8610384773594008094f45d68f31b3c9ac84ff0d07b86c59b753a60b1e3808029a052e5246c9a404f756a246b8cec545099741aeb4e6e0add935a5b7a366fa88f95a0538eaa2421e50377c534244dcdcd15ace00bf9c0adbd9eb162baae2b9e89a36f\"],\"method\":\"eth_sendRawTransaction\"} Error: intrinsic gas too low\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:72360:28\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103521:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27180:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27024:25)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:106691:25\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103501:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at iterateeCallback (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27014:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27196:16\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103503:9\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27315:16\n at replenish (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27029:17)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:27033:9\n at eachLimit (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:26723:36)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:26937:16\n at end (chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:103498:5)\n at chrome-extension://kedndjddlegigbgiknllkjcmbpcnoakf/scripts/background.js:106913:40"}}]],"id":4068311466147836,"loadingDefaults":false,"metamaskNetworkId":"1","nonceDetails":{"local":{"details":{"highest":3,"startPoint":3},"name":"local","nonce":3},"network":{"details":{"baseCount":3},"name":"network","nonce":3},"params":{"highestLocalNonce":3,"highestSuggested":3,"nextNetworkNonce":3}},"rawTx":"0xf8610384773594008094f45d68f31b3c9ac84ff0d07b86c59b753a60b1e3808029a052e5246c9a404f756a246b8cec545099741aeb4e6e0add935a5b7a366fa88f95a0538eaa2421e50377c534244dcdcd15ace00bf9c0adbd9eb162baae2b9e89a36f","status":"failed","time":1522378334455,"txParams":{"chainId":"0x3","from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","gas":"0x0","gasPrice":"0x77359400","nonce":"0x3","to":"0xf45d68f31b3c9ac84ff0d07b86c59b753a60b1e3","value":"0x0"}}, + {"id":2315363930841933,"time":1522378572149,"status":"approved","metamaskNetworkId":"1","loadingDefaults":false,"txParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","to":"0xf45d68f31b3c9ac84ff0d07b86c59b753a60b1e3","value":"0x0","gas":"0x0","gasPrice":"0x5f5e100"},"history":[{"id":2315363930841933,"time":1522378572149,"status":"unapproved","metamaskNetworkId":"1","loadingDefaults":true,"txParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","to":"0xf45d68f31b3c9ac84ff0d07b86c59b753a60b1e3","value":"0x0","gas":"0xcf08","gasPrice":"0x5f5e100"}},[{"op":"replace","path":"/loadingDefaults","value":false},{"op":"add","path":"/gasPriceSpecified","value":true},{"op":"add","path":"/gasLimitSpecified","value":true},{"op":"add","path":"/estimatedGas","value":"0xcf08"}],[{"op":"replace","path":"/txParams/gas","value":"0x0","note":"confTx: user approved transaction"}],[{"op":"replace","path":"/status","value":"approved","note":"txStateManager: setting status to approved"}]],"gasPriceSpecified":true,"gasLimitSpecified":true,"estimatedGas":"0xcf08"}, + {"estimatedGas":"8d41","firstRetryBlockNumber":"0x2cbc70","gasLimitSpecified":false,"gasPriceSpecified":false,"hash":"0xfbd997bf9bb85ca1598952ca23e7910502d527e06cb6ee1bbe7e7dd59d6909cd","history":[{"id":2079438776801906,"loadingDefaults":true,"metamaskNetworkId":"1","status":"unapproved","time":1522346270251,"txParams":{"data":"0xa9059cbb000000000000000000000000e7884118ee52ec3f4eef715cb022279d7d4181a9000000000000000000000000000000000000000000000000000000000000000b","from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","to":"0x66f30b996a7d345cd00badcfe75e81e25dc5e1eb"}},[{"op":"add","path":"/txParams/gasPrice","value":"0x37e11d600"},{"op":"add","path":"/txParams/value","value":"0x0"},{"op":"add","path":"/txParams/gas","value":"0xd3e1"},{"op":"replace","path":"/loadingDefaults","value":false},{"op":"add","path":"/gasPriceSpecified","value":false},{"op":"add","path":"/gasLimitSpecified","value":false},{"op":"add","path":"/estimatedGas","value":"8d41"}],[{"note":"confTx: user approved transaction","op":"replace","path":"/txParams/gasPrice","value":"0x5f5e100"}],[{"note":"txStateManager: setting status to approved","op":"replace","path":"/status","value":"approved"}],[{"note":"transactions#approveTransaction","op":"add","path":"/txParams/nonce","value":"0x2"},{"op":"add","path":"/nonceDetails","value":{"local":{"details":{"highest":2,"startPoint":2},"name":"local","nonce":2},"network":{"details":{"baseCount":2},"name":"network","nonce":2},"params":{"highestLocalNonce":2,"highestSuggested":2,"nextNetworkNonce":2}}}],[{"note":"txStateManager: setting status to signed","op":"add","path":"/txParams/chainId","value":"0x3"},{"op":"replace","path":"/status","value":"signed"}],[{"note":"transactions#publishTransaction","op":"add","path":"/rawTx","value":"0xf8a8028405f5e10082d3e19466f30b996a7d345cd00badcfe75e81e25dc5e1eb80b844a9059cbb000000000000000000000000e7884118ee52ec3f4eef715cb022279d7d4181a9000000000000000000000000000000000000000000000000000000000000000b2aa05cb38a3a68e49008da2e93839f6dedeb96b1630c2a73c4cf5eb3fcc74299a100a039f17c0807469bd101165fa0749dc7065832b4a7c3a382b6cf7e29228c2a683d"}],[{"note":"transactions#setTxHash","op":"add","path":"/hash","value":"0xfbd997bf9bb85ca1598952ca23e7910502d527e06cb6ee1bbe7e7dd59d6909cd"}],[{"note":"txStateManager - add submitted time stamp","op":"add","path":"/submittedTime","value":1522346282571}],[{"note":"txStateManager: setting status to submitted","op":"replace","path":"/status","value":"submitted"}],[{"note":"transactions/pending-tx-tracker#event: tx:block-update","op":"add","path":"/firstRetryBlockNumber","value":"0x2cbc70"}],[{"note":"txStateManager: setting status to confirmed","op":"replace","path":"/status","value":"confirmed"}]],"id":2079438776801906,"loadingDefaults":false,"metamaskNetworkId":"1","nonceDetails":{"local":{"details":{"highest":2,"startPoint":2},"name":"local","nonce":2},"network":{"details":{"baseCount":2},"name":"network","nonce":2},"params":{"highestLocalNonce":2,"highestSuggested":2,"nextNetworkNonce":2}},"rawTx":"0xf8a8028405f5e10082d3e19466f30b996a7d345cd00badcfe75e81e25dc5e1eb80b844a9059cbb000000000000000000000000e7884118ee52ec3f4eef715cb022279d7d4181a9000000000000000000000000000000000000000000000000000000000000000b2aa05cb38a3a68e49008da2e93839f6dedeb96b1630c2a73c4cf5eb3fcc74299a100a039f17c0807469bd101165fa0749dc7065832b4a7c3a382b6cf7e29228c2a683d","status":"confirmed","submittedTime":1522346282571,"time":1522346270251,"txParams":{"chainId":"0x3","data":"0xa9059cbb000000000000000000000000e7884118ee52ec3f4eef715cb022279d7d4181a9000000000000000000000000000000000000000000000000000000000000000b","from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","gas":"0xd3e1","gasPrice":"0x5f5e100","nonce":"0x2","to":"0x66f30b996a7d345cd00badcfe75e81e25dc5e1eb","value":"0x0"}}, + {"id":4087002078467524,"time":1522379587999,"status":"submitted","metamaskNetworkId":"1","loadingDefaults":false,"txParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","to":"0xf45d68f31b3c9ac84ff0d07b86c59b753a60b1e3","value":"0x0","gas":"0xcf08","gasPrice":"0x5f5e100","nonce":"0x3","chainId":"0x3"},"history":[{"id":4087002078467524,"time":1522379587999,"status":"unapproved","metamaskNetworkId":"1","loadingDefaults":true,"txParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","to":"0xf45d68f31b3c9ac84ff0d07b86c59b753a60b1e3","value":"0x0","gas":"0xcf08","gasPrice":"0x5f5e100"}},[{"op":"replace","path":"/loadingDefaults","value":false},{"op":"add","path":"/gasPriceSpecified","value":true},{"op":"add","path":"/gasLimitSpecified","value":true},{"op":"add","path":"/estimatedGas","value":"0xcf08"}],[],[{"op":"replace","path":"/status","value":"approved","note":"txStateManager: setting status to approved"}],[{"op":"add","path":"/txParams/nonce","value":"0x3","note":"transactions#approveTransaction"},{"op":"add","path":"/nonceDetails","value":{"params":{"highestLocalNonce":3,"highestSuggested":3,"nextNetworkNonce":3},"local":{"name":"local","nonce":3,"details":{"startPoint":3,"highest":3}},"network":{"name":"network","nonce":3,"details":{"baseCount":3}}}}],[{"op":"add","path":"/txParams/chainId","value":"0x3","note":"txStateManager: setting status to signed"},{"op":"replace","path":"/status","value":"signed"}],[{"op":"add","path":"/rawTx","value":"0xf863038405f5e10082cf0894f45d68f31b3c9ac84ff0d07b86c59b753a60b1e3808029a0d64ed427733ef67fe788fe85d3cfe51c43cfc83d07fa4ab8af5d3bc8c8199895a02699c131cc0ffcf842b54776ac611bdd165fdb87dd3ecff1554ec8da1bf3ff39","note":"transactions#publishTransaction"}],[{"op":"add","path":"/hash","value":"0x52f0929fc143d76f4e6255d95cebfc76b74f43726191bd4081a5ae9bd6c1fa4a","note":"transactions#setTxHash"}],[{"op":"add","path":"/submittedTime","value":1522379590158,"note":"txStateManager - add submitted time stamp"}],[{"op":"replace","path":"/status","value":"submitted","note":"txStateManager: setting status to submitted"}],[{"op":"add","path":"/firstRetryBlockNumber","value":"0x2cc718","note":"transactions/pending-tx-tracker#event: tx:block-update"}]],"gasPriceSpecified":true,"gasLimitSpecified":true,"estimatedGas":"0xcf08","nonceDetails":{"params":{"highestLocalNonce":3,"highestSuggested":3,"nextNetworkNonce":3},"local":{"name":"local","nonce":3,"details":{"startPoint":3,"highest":3}},"network":{"name":"network","nonce":3,"details":{"baseCount":3}}},"rawTx":"0xf863038405f5e10082cf0894f45d68f31b3c9ac84ff0d07b86c59b753a60b1e3808029a0d64ed427733ef67fe788fe85d3cfe51c43cfc83d07fa4ab8af5d3bc8c8199895a02699c131cc0ffcf842b54776ac611bdd165fdb87dd3ecff1554ec8da1bf3ff39","hash":"0x52f0929fc143d76f4e6255d95cebfc76b74f43726191bd4081a5ae9bd6c1fa4a","submittedTime":1522379590158,"firstRetryBlockNumber":"0x2cc718"}, + {"estimatedGas":"0x5208","gasLimitSpecified":false,"gasPriceSpecified":false,"history":[{"id":6301441591225658,"loadingDefaults":true,"metamaskNetworkId":"1","status":"unapproved","time":1522346051227,"txParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","to":"0x81b7e08f65bdf5648606c89998a9cc8164397647","value":"0xde0b6b3a7640000"}},[{"op":"add","path":"/txParams/gasPrice","value":"0x4a817c800"},{"op":"add","path":"/txParams/gas","value":"0x5208"},{"op":"replace","path":"/loadingDefaults","value":false},{"op":"add","path":"/gasPriceSpecified","value":false},{"op":"add","path":"/gasLimitSpecified","value":false},{"op":"add","path":"/simpleSend","value":true},{"op":"add","path":"/estimatedGas","value":"0x5208"}],[{"note":"txStateManager: setting status to rejected","op":"replace","path":"/status","value":"rejected"}]],"id":6301441591225658,"loadingDefaults":false,"metamaskNetworkId":"1","simpleSend":true,"status":"rejected","time":1522346051227,"txParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","gas":"0x5208","gasPrice":"0x4a817c800","to":"0x81b7e08f65bdf5648606c89998a9cc8164397647","value":"0xde0b6b3a7640000"}}, + {"id":2699829174766090,"time":1522381785750,"status":"unapproved","metamaskNetworkId":"1","loadingDefaults":false,"txParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","to":"0xf45d68f31b3c9ac84ff0d07b86c59b753a60b1e3","value":"0x0","gas":"0xcf08","gasPrice":"0x5f5e100"},"history":[{"id":2699829174766090,"time":1522381785750,"status":"unapproved","metamaskNetworkId":"1","loadingDefaults":true,"txParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","to":"0xf45d68f31b3c9ac84ff0d07b86c59b753a60b1e3","value":"0x0","gas":"0xcf08","gasPrice":"0x5f5e100"}},[{"op":"replace","path":"/loadingDefaults","value":false},{"op":"add","path":"/gasPriceSpecified","value":true},{"op":"add","path":"/gasLimitSpecified","value":true},{"op":"add","path":"/estimatedGas","value":"0xcf08"}]],"gasPriceSpecified":true,"gasLimitSpecified":true,"estimatedGas":"0xcf08"} + ], + "unapprovedTxs": {"2699829174766090":{"id":2699829174766090,"time":1522381785750,"status":"unapproved","metamaskNetworkId":"1","loadingDefaults":false,"txParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","to":"0xf45d68f31b3c9ac84ff0d07b86c59b753a60b1e3","value":"0x0","gas":"0xcf08","gasPrice":"0x5f5e100"},"history":[{"id":2699829174766090,"time":1522381785750,"status":"unapproved","metamaskNetworkId":"1","loadingDefaults":true,"txParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","to":"0xf45d68f31b3c9ac84ff0d07b86c59b753a60b1e3","value":"0x0","gas":"0xcf08","gasPrice":"0x5f5e100"}},[{"op":"replace","path":"/loadingDefaults","value":false},{"op":"add","path":"/gasPriceSpecified","value":true},{"op":"add","path":"/gasLimitSpecified","value":true},{"op":"add","path":"/estimatedGas","value":"0xcf08"}]],"gasPriceSpecified":true,"gasLimitSpecified":true,"estimatedGas":"0xcf08"}}, + "unapprovedMsgs": {"2315363930841932":{"id":2315363930841932,"msgParams":{"from":"0x5b1cbd5636d484bf1cb6927a9425db9e7dc73ce4","data":"0x879a053d4800c6354e76c7985a865d2922c82fb5b3f4577b2fe08b998954f2e0"},"time":1522378539686,"status":"unapproved","type":"eth_sign"}}, + "unapprovedMsgCount": 0, + "unapprovedPersonalMsgs": {}, + "unapprovedPersonalMsgCount": 0, + "keyringTypes": [ + "Simple Key Pair", + "HD Key Tree" + ], + "keyrings": [ + { + "type": "HD Key Tree", + "accounts": [ + "fdea65c8e26263f6d9a1b5de9555d2931a33b825", + "c5b8dbac4c1d3f152cdeb400e2313f309c410acb", + "2f8d4a878cfa04a6e60d46362f5644deab66572d" + ] + }, + { + "type": "Simple Key Pair", + "accounts": [ + "0xd85a4b6a394794842887b8284293d69163007bbb" + ] + } + ], + "selectedAddress": "0xd85a4b6a394794842887b8284293d69163007bbb", + "provider": { + "type": "testnet" + }, + "shapeShiftTxList": [{"depositAddress":"34vJ3AfmNcLiziA4VFgEVcQTwxVLD1qkke","depositType":"BTC","key":"shapeshift","response":{"status":"no_deposits","address":"34vJ3AfmNcLiziA4VFgEVcQTwxVLD1qkke"},"time":1522377459106}], + "lostAccounts": [], + "send": {}, + "currentLocale": "en" + }, + "appState": { + "menuOpen": false, + "currentView": { + "name": "confTx", + "detailView": null, + "context": 0 + }, + "accountDetail": { + "subview": "transactions" + }, + "modal": { + "modalState": {}, + "previousModalState": {} + }, + "transForward": true, + "isLoading": false, + "warning": null, + "scrollToBottom": false, + "forgottenPassword": null + }, + "identities": {} +} diff --git a/development/verify-locale-strings.js b/development/verify-locale-strings.js index b8fe5a7dc..8dc0a30f1 100644 --- a/development/verify-locale-strings.js +++ b/development/verify-locale-strings.js @@ -10,87 +10,88 @@ // //////////////////////////////////////////////////////////////////////////////// -var fs = require('fs') -var path = require('path') +const fs = require('fs') +const path = require('path') +const localeIndex = require('../app/_locales/index.json') console.log('Locale Verification') -var locale = process.argv[2] -if (!locale || locale == '') { - console.log('Must enter a locale as argument. exitting') - process.exit(1) +const specifiedLocale = process.argv[2] +if (specifiedLocale) { + console.log(`Verifying selected locale "${specifiedLocale}":\n\n`) + const locale = localeIndex.find(localeMeta => localeMeta.code === specifiedLocale) + verifyLocale({ localeMeta }) +} else { + console.log('Verifying all locales:\n\n') + localeIndex.forEach(localeMeta => { + verifyLocale({ localeMeta }) + console.log('\n') + }) } -console.log("verifying for locale " + locale) -localeFilePath = path.join(process.cwd(), 'app', '_locales', locale, 'messages.json') -try { - localeObj = JSON.parse(fs.readFileSync(localeFilePath, 'utf8')); -} catch (e) { - if(e.code == 'ENOENT') { - console.log('Locale file not found') - } else { - console.log('Error opening your locale file: ', e) + +function verifyLocale({ localeMeta }) { + const localeCode = localeMeta.code + const localeName = localeMeta.name + + try { + const localeFilePath = path.join(process.cwd(), 'app', '_locales', localeCode, 'messages.json') + targetLocale = JSON.parse(fs.readFileSync(localeFilePath, 'utf8')); + } catch (e) { + if (e.code == 'ENOENT') { + console.log('Locale file not found') + } else { + console.log(`Error opening your locale ("${localeCode}") file: `, e) + } + process.exit(1) } - process.exit(1) -} -englishFilePath = path.join(process.cwd(), 'app', '_locales', 'en', 'messages.json') -try { - englishObj = JSON.parse(fs.readFileSync(englishFilePath, 'utf8')); -} catch (e) { - if(e.code == 'ENOENT') { - console.log("English File not found") - } else { - console.log("Error opening english locale file: ", e) + try { + const englishFilePath = path.join(process.cwd(), 'app', '_locales', 'en', 'messages.json') + englishLocale = JSON.parse(fs.readFileSync(englishFilePath, 'utf8')); + } catch (e) { + if(e.code == 'ENOENT') { + console.log('English File not found') + } else { + console.log('Error opening english locale file: ', e) + } + process.exit(1) } - process.exit(1) -} -console.log('\tverifying whether all your locale strings are contained in the english one') + // console.log(' verifying whether all your locale ("${localeCode}") strings are contained in the english one') + const extraItems = compareLocalesForMissingItems({ base: targetLocale, subject: englishLocale }) + // console.log('\n verifying whether your locale ("${localeCode}") contains all english strings') + const missingItems = compareLocalesForMissingItems({ base: englishLocale, subject: targetLocale }) -var counter = 0 -var foundErrorA = false -var notFound = []; -Object.keys(localeObj).forEach(function(key){ - if (!englishObj[key]) { - foundErrorA = true - notFound.push(key) - } - counter++ -}) + const englishEntryCount = Object.keys(englishLocale).length + const coveragePercent = 100 * (englishEntryCount - missingItems.length) / englishEntryCount -if (foundErrorA) { - console.log('\nThe following string(s) is(are) not found in the english locale:') - notFound.forEach(function(key) { - console.log(key) - }) -} else { - console.log('\tall ' + counter +' strings declared in your locale were found in the english one') -} + console.log(`Status of **${localeName} (${localeCode})** ${coveragePercent.toFixed(2)}% coverage:`) -console.log('\n\tverifying whether your locale contains all english strings') + if (extraItems.length) { + console.log('\nMissing from english locale:') + extraItems.forEach(function(key) { + console.log(` - [ ] ${key}`) + }) + } else { + // console.log(` all ${counter} strings declared in your locale ("${localeCode}") were found in the english one`) + } -var counter = 0 -var foundErrorB = false -var notFound = []; -Object.keys(englishObj).forEach(function(key){ - if (!localeObj[key]) { - foundErrorB = true - notFound.push(key) + if (missingItems.length) { + console.log(`\nMissing:`) + missingItems.forEach(function(key) { + console.log(` - [ ] ${key}`) + }) + } else { + // console.log(` all ${counter} english strings were found in your locale ("${localeCode}")!`) } - counter++ -}) -if (foundErrorB) { - console.log('\nThe following string(s) is(are) not found in the your locale:') - notFound.forEach(function(key) { - console.log(key) - }) -} else { - console.log('\tall ' + counter +' english strings were found in your locale!') + if (!extraItems.length && !missingItems.length) { + console.log('Full coverage : )') + } } -if (!foundErrorA && !foundErrorB) { - console.log('You are good to go') -}
\ No newline at end of file +function compareLocalesForMissingItems({ base, subject }) { + return Object.keys(base).filter((key) => !subject[key]) +} diff --git a/docs/translating-guide.md b/docs/translating-guide.md index ae2dfecd3..8b2bc1785 100644 --- a/docs/translating-guide.md +++ b/docs/translating-guide.md @@ -6,9 +6,12 @@ The MetaMask browser extension supports new translations added in the form of ne ## Adding a new Language -Each supported language is represented by a folder in `app/_locales` whose name is that language's subtag ([look up a language subtag using this tool](https://r12a.github.io/app-subtags/)). +- Each supported language is represented by a folder in `app/_locales` whose name is that language's subtag (example: `app/_locales/es/`). (look up a language subtag using the [r12a "Find" tool](https://r12a.github.io/app-subtags/) or this [wikipedia list](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes)). +- Inside that folder there should be a `messages.json`. +- An easy way to start your translation is to first **make a copy** of `app/_locales/en/messages.json` (the english translation), and then **translate the `message` key** for each in-app message. +- **The `description` key** is just to add context for what the translation is about, it **does not need to be translated**. +- Add the language to the [locales index](https://github.com/MetaMask/metamask-extension/blob/master/app/_locales/index.json) `app/_locales/index.json` -Inside that folder there should be a `messages.json` file that follows the specified format. An easy way to start your translation is to first duplicate `app/_locales/en/messages.json` (the english translation), and then update the `message` key for each in-app message. That's it! When MetaMask is loaded on a computer with that language set as the system language, they will see your translation instead of the default one. @@ -20,7 +23,7 @@ To automatically see if you are missing any phrases to translate, we have a scri node development/verify-locale-strings.js $YOUR_LOCALE ``` -Where `$YOUR_LOCALE` is your [locale string](https://r12a.github.io/app-subtags/), i.e. the name of your language folder. +Where `$YOUR_LOCALE` is your locale string (example: `es`), i.e. the name of your language folder. To verify that your translation works in the app, you will need to [build a local copy](https://github.com/MetaMask/metamask-extension#building-locally) of MetaMask. You will need to change your browser language, your operating system language, and restart your browser (sorry it's so much work!). diff --git a/gulpfile.js b/gulpfile.js index f57ea6206..4f0da9d60 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,37 +1,55 @@ -var watchify = require('watchify') -var browserify = require('browserify') -var disc = require('disc') -var gulp = require('gulp') -var source = require('vinyl-source-stream') -var buffer = require('vinyl-buffer') -var gutil = require('gulp-util') -var watch = require('gulp-watch') -var sourcemaps = require('gulp-sourcemaps') -var jsoneditor = require('gulp-json-editor') -var zip = require('gulp-zip') -var assign = require('lodash.assign') -var livereload = require('gulp-livereload') -var del = require('del') -var eslint = require('gulp-eslint') -var fs = require('fs') -var path = require('path') -var manifest = require('./app/manifest.json') -var gulpif = require('gulp-if') -var replace = require('gulp-replace') -var mkdirp = require('mkdirp') -var asyncEach = require('async/each') -var exec = require('child_process').exec -var sass = require('gulp-sass') -var autoprefixer = require('gulp-autoprefixer') -var gulpStylelint = require('gulp-stylelint') -var stylefmt = require('gulp-stylefmt') -var uglify = require('gulp-uglify-es').default -var babel = require('gulp-babel') - - -var disableDebugTools = gutil.env.disableDebugTools -var debug = gutil.env.debug +const watchify = require('watchify') +const browserify = require('browserify') +const envify = require('envify/custom') +const disc = require('disc') +const gulp = require('gulp') +const source = require('vinyl-source-stream') +const buffer = require('vinyl-buffer') +const gutil = require('gulp-util') +const watch = require('gulp-watch') +const sourcemaps = require('gulp-sourcemaps') +const jsoneditor = require('gulp-json-editor') +const zip = require('gulp-zip') +const assign = require('lodash.assign') +const livereload = require('gulp-livereload') +const del = require('del') +const eslint = require('gulp-eslint') +const fs = require('fs') +const path = require('path') +const manifest = require('./app/manifest.json') +const replace = require('gulp-replace') +const mkdirp = require('mkdirp') +const asyncEach = require('async/each') +const exec = require('child_process').exec +const sass = require('gulp-sass') +const autoprefixer = require('gulp-autoprefixer') +const gulpStylelint = require('gulp-stylelint') +const stylefmt = require('gulp-stylefmt') +const uglify = require('gulp-uglify-es').default +const babel = require('gulp-babel') +const debug = require('gulp-debug') +const pify = require('pify') +const gulpMultiProcess = require('gulp-multi-process') +const endOfStream = pify(require('end-of-stream')) + +function gulpParallel (...args) { + return function spawnGulpChildProcess(cb) { + return gulpMultiProcess(args, cb, true) + } +} +const browserPlatforms = [ + 'firefox', + 'chrome', + 'edge', + 'opera', +] +const commonPlatforms = [ + // browser webapp + 'mascara', + // browser extensions + ...browserPlatforms +] // browser reload @@ -41,65 +59,98 @@ gulp.task('dev:reload', function() { }) }) +// copy universal -// copy static +const copyTaskNames = [] +const copyDevTaskNames = [] -gulp.task('copy:locales', copyTask({ +createCopyTasks('locales', { source: './app/_locales/', - destinations: [ - './dist/firefox/_locales', - './dist/chrome/_locales', - './dist/edge/_locales', - './dist/opera/_locales', - ] -})) -gulp.task('copy:images', copyTask({ + destinations: commonPlatforms.map(platform => `./dist/${platform}/_locales`), +}) +createCopyTasks('images', { source: './app/images/', - destinations: [ - './dist/firefox/images', - './dist/chrome/images', - './dist/edge/images', - './dist/opera/images', - ], -})) -gulp.task('copy:contractImages', copyTask({ + destinations: commonPlatforms.map(platform => `./dist/${platform}/images`), +}) +createCopyTasks('contractImages', { source: './node_modules/eth-contract-metadata/images/', - destinations: [ - './dist/firefox/images/contract', - './dist/chrome/images/contract', - './dist/edge/images/contract', - './dist/opera/images/contract', - ], -})) -gulp.task('copy:fonts', copyTask({ + destinations: commonPlatforms.map(platform => `./dist/${platform}/images/contract`), +}) +createCopyTasks('fonts', { source: './app/fonts/', - destinations: [ - './dist/firefox/fonts', - './dist/chrome/fonts', - './dist/edge/fonts', - './dist/opera/fonts', - ], -})) -gulp.task('copy:reload', copyTask({ + destinations: commonPlatforms.map(platform => `./dist/${platform}/fonts`), +}) +createCopyTasks('reload', { + devOnly: true, source: './app/scripts/', - destinations: [ - './dist/firefox/scripts', - './dist/chrome/scripts', - './dist/edge/scripts', - './dist/opera/scripts', - ], pattern: '/chromereload.js', -})) -gulp.task('copy:root', copyTask({ + destinations: commonPlatforms.map(platform => `./dist/${platform}`), +}) +createCopyTasks('html', { source: './app/', - destinations: [ - './dist/firefox', - './dist/chrome', - './dist/edge', - './dist/opera', - ], - pattern: '/*', -})) + pattern: '/*.html', + destinations: commonPlatforms.map(platform => `./dist/${platform}`), +}) + +// copy extension + +createCopyTasks('manifest', { + source: './app/', + pattern: '/*.json', + destinations: browserPlatforms.map(platform => `./dist/${platform}`), +}) + +// copy mascara + +createCopyTasks('html:mascara', { + source: './mascara/', + pattern: 'proxy/index.html', + destinations: [`./dist/mascara/`], +}) + +function createCopyTasks(label, opts) { + if (!opts.devOnly) { + const copyTaskName = `copy:${label}` + copyTask(copyTaskName, opts) + copyTaskNames.push(copyTaskName) + } + const copyDevTaskName = `dev:copy:${label}` + copyTask(copyDevTaskName, Object.assign({ devMode: true }, opts)) + copyDevTaskNames.push(copyDevTaskName) +} + +function copyTask(taskName, opts){ + const source = opts.source + const destination = opts.destination + const destinations = opts.destinations || [destination] + const pattern = opts.pattern || '/**/*' + const devMode = opts.devMode + + return gulp.task(taskName, function () { + if (devMode) { + watch(source + pattern, (event) => { + livereload.changed(event.path) + performCopy() + }) + } + + return performCopy() + }) + + function performCopy() { + // stream from source + let stream = gulp.src(source + pattern, { base: source }) + + // copy to destinations + destinations.forEach(function(destination) { + stream = stream.pipe(gulp.dest(destination)) + }) + + return stream + } +} + +// manifest tinkering gulp.task('manifest:chrome', function() { return gulp.src('./dist/chrome/manifest.json') @@ -134,52 +185,40 @@ gulp.task('manifest:production', function() { ],{base: './dist/'}) // Exclude chromereload script in production: - .pipe(gulpif(!debug,jsoneditor(function(json) { + .pipe(jsoneditor(function(json) { json.background.scripts = json.background.scripts.filter((script) => { return !script.includes('chromereload') }) return json - }))) + })) .pipe(gulp.dest('./dist/', { overwrite: true })) }) -const staticFiles = [ - 'locales', - 'images', - 'fonts', - 'root' -] - -var copyStrings = staticFiles.map(staticFile => `copy:${staticFile}`) -copyStrings.push('copy:contractImages') - -if (debug) { - copyStrings.push('copy:reload') -} - -gulp.task('copy', gulp.series(gulp.parallel(...copyStrings), 'manifest:production', 'manifest:chrome', 'manifest:opera')) -gulp.task('copy:watch', function(){ - gulp.watch(['./app/{_locales,images}/*', './app/scripts/chromereload.js', './app/*.{html,json}'], gulp.series('copy')) -}) - -// record deps - -gulp.task('deps', function (cb) { - exec('npm ls', (err, stdoutOutput, stderrOutput) => { - if (err) return cb(err) - const browsers = ['firefox','chrome','edge','opera'] - asyncEach(browsers, (target, done) => { - fs.writeFile(`./dist/${target}/deps.txt`, stdoutOutput, done) - }, cb) - }) -}) +gulp.task('copy', + gulp.series( + gulp.parallel(...copyTaskNames), + 'manifest:production', + 'manifest:chrome', + 'manifest:opera' + ) +) + +gulp.task('dev:copy', + gulp.series( + gulp.parallel(...copyDevTaskNames), + 'manifest:chrome', + 'manifest:opera' + ) +) // lint js +const lintTargets = ['app/**/*.json', 'app/**/*.js', '!app/scripts/vendor/**/*.js', 'ui/**/*.js', 'old-ui/**/*.js', 'mascara/src/*.js', 'mascara/server/*.js', '!node_modules/**', '!dist/firefox/**', '!docs/**', '!app/scripts/chromereload.js', '!mascara/test/jquery-3.1.0.min.js'] + gulp.task('lint', function () { // Ignoring node_modules, dist/firefox, and docs folders: - return gulp.src(['app/**/*.js', '!app/scripts/vendor/**/*.js', 'ui/**/*.js', 'mascara/src/*.js', 'mascara/server/*.js', '!node_modules/**', '!dist/firefox/**', '!docs/**', '!app/scripts/chromereload.js', '!mascara/test/jquery-3.1.0.min.js']) + return gulp.src(lintTargets) .pipe(eslint(fs.readFileSync(path.join(__dirname, '.eslintrc')))) // eslint.format() outputs the lint results to the console. // Alternatively use eslint.formatEach() (see Docs). @@ -190,47 +229,55 @@ gulp.task('lint', function () { }); gulp.task('lint:fix', function () { - return gulp.src(['app/**/*.js', 'ui/**/*.js', 'mascara/src/*.js', 'mascara/server/*.js', '!node_modules/**', '!dist/firefox/**', '!docs/**', '!app/scripts/chromereload.js', '!mascara/test/jquery-3.1.0.min.js']) + return gulp.src(lintTargets) .pipe(eslint(Object.assign(fs.readFileSync(path.join(__dirname, '.eslintrc')), {fix: true}))) .pipe(eslint.format()) .pipe(eslint.failAfterError()) }); -/* -gulp.task('default', ['lint'], function () { - // This will only run if the lint task is successful... -}); -*/ +// scss compilation and autoprefixing tasks -// build js +gulp.task('build:scss', createScssBuildTask({ + src: 'ui/app/css/index.scss', + dest: 'ui/app/css/output', + devMode: false, +})) -const jsFiles = [ - 'inpage', - 'contentscript', - 'background', - 'popup', -] +gulp.task('dev:scss', createScssBuildTask({ + src: 'ui/app/css/index.scss', + dest: 'ui/app/css/output', + devMode: true, + pattern: 'ui/app/css/**/*.scss', +})) -// scss compilation and autoprefixing tasks +function createScssBuildTask({ src, dest, devMode, pattern }) { + return function () { + if (devMode) { + watch(pattern, async (event) => { + const stream = buildScss() + await endOfStream(stream) + livereload.changed(event.path) + }) + } + return buildScss() + } -gulp.task('build:scss', function () { - return gulp.src('ui/app/css/index.scss') - .pipe(sourcemaps.init()) - .pipe(sass().on('error', sass.logError)) - .pipe(sourcemaps.write()) - .pipe(autoprefixer()) - .pipe(gulp.dest('ui/app/css/output')) -}) -gulp.task('watch:scss', function() { - gulp.watch(['ui/app/css/**/*.scss'], gulp.series(['build:scss'])) -}) + function buildScss() { + return gulp.src(src) + .pipe(sourcemaps.init()) + .pipe(sass().on('error', sass.logError)) + .pipe(sourcemaps.write()) + .pipe(autoprefixer()) + .pipe(gulp.dest(dest)) + } +} gulp.task('lint-scss', function() { return gulp .src('ui/app/css/itcss/**/*.scss') .pipe(gulpStylelint({ reporters: [ - {formatter: 'string', console: true} + { formatter: 'string', console: true } ], fix: true, })); @@ -242,46 +289,84 @@ gulp.task('fmt-scss', function () { .pipe(gulp.dest('ui/app/css/itcss')); }); -// bundle tasks +// build js -var jsDevStrings = jsFiles.map(jsFile => `dev:js:${jsFile}`) -var jsBuildStrings = jsFiles.map(jsFile => `build:js:${jsFile}`) +const buildJsFiles = [ + 'inpage', + 'contentscript', + 'background', + 'ui', +] -jsFiles.forEach((jsFile) => { - gulp.task(`dev:js:${jsFile}`, bundleTask({ - watch: true, - label: jsFile, - filename: `${jsFile}.js`, - isBuild: false - })) - gulp.task(`build:js:${jsFile}`, bundleTask({ - watch: false, - label: jsFile, - filename: `${jsFile}.js`, - isBuild: true - })) -}) +// bundle tasks +createTasksForBuildJsExtension({ buildJsFiles, taskPrefix: 'dev:extension:js', devMode: true }) +createTasksForBuildJsExtension({ buildJsFiles, taskPrefix: 'build:extension:js' }) +createTasksForBuildJsMascara({ taskPrefix: 'build:mascara:js' }) +createTasksForBuildJsMascara({ taskPrefix: 'dev:mascara:js', devMode: true }) + +function createTasksForBuildJsExtension({ buildJsFiles, taskPrefix, devMode, bundleTaskOpts = {} }) { + // inpage must be built before all other scripts: + const rootDir = './app/scripts' + const nonInpageFiles = buildJsFiles.filter(file => file !== 'inpage') + const buildPhase1 = ['inpage'] + const buildPhase2 = nonInpageFiles + const destinations = browserPlatforms.map(platform => `./dist/${platform}`) + bundleTaskOpts = Object.assign({ + buildSourceMaps: true, + sourceMapDir: devMode ? './' : '../sourcemaps', + minifyBuild: !devMode, + buildWithFullPaths: devMode, + watch: devMode, + devMode, + }, bundleTaskOpts) + createTasksForBuildJs({ rootDir, taskPrefix, bundleTaskOpts, destinations, buildPhase1, buildPhase2 }) +} -// inpage must be built before all other scripts: -const firstDevString = jsDevStrings.shift() -gulp.task('dev:js', gulp.series(firstDevString, gulp.parallel(...jsDevStrings))) +function createTasksForBuildJsMascara({ taskPrefix, devMode, bundleTaskOpts = {} }) { + // inpage must be built before all other scripts: + const rootDir = './mascara/src/' + const buildPhase1 = ['ui', 'proxy', 'background', 'metamascara'] + const destinations = ['./dist/mascara'] + bundleTaskOpts = Object.assign({ + buildSourceMaps: true, + sourceMapDir: './', + minifyBuild: !devMode, + buildWithFullPaths: devMode, + watch: devMode, + devMode, + }, bundleTaskOpts) + createTasksForBuildJs({ rootDir, taskPrefix, bundleTaskOpts, destinations, buildPhase1 }) +} + +function createTasksForBuildJs({ rootDir, taskPrefix, bundleTaskOpts, destinations, buildPhase1 = [], buildPhase2 = [] }) { + // bundle task for each file + const jsFiles = [].concat(buildPhase1, buildPhase2) + jsFiles.forEach((jsFile) => { + gulp.task(`${taskPrefix}:${jsFile}`, bundleTask(Object.assign({ + label: jsFile, + filename: `${jsFile}.js`, + filepath: `${rootDir}/${jsFile}.js`, + destinations, + }, bundleTaskOpts))) + }) + // compose into larger task + const subtasks = [] + subtasks.push(gulp.parallel(buildPhase1.map(file => `${taskPrefix}:${file}`))) + if (buildPhase2.length) subtasks.push(gulp.parallel(buildPhase2.map(file => `${taskPrefix}:${file}`))) -// inpage must be built before all other scripts: -const firstBuildString = jsBuildStrings.shift() -gulp.task('build:js', gulp.series(firstBuildString, gulp.parallel(...jsBuildStrings))) + gulp.task(taskPrefix, gulp.series(subtasks)) +} // disc bundle analyzer tasks -jsFiles.forEach((jsFile) => { - gulp.task(`disc:${jsFile}`, discTask({ label: jsFile, filename: `${jsFile}.js` })) +buildJsFiles.forEach((jsFile) => { + gulp.task(`disc:${jsFile}`, discTask({ label: jsFile, filename: `${jsFile}.js` })) }) -gulp.task('disc', gulp.parallel(jsFiles.map(jsFile => `disc:${jsFile}`))) - +gulp.task('disc', gulp.parallel(buildJsFiles.map(jsFile => `disc:${jsFile}`))) // clean dist - gulp.task('clean', function clean() { return del(['./dist/*']) }) @@ -293,40 +378,88 @@ gulp.task('zip:edge', zipTask('edge')) gulp.task('zip:opera', zipTask('opera')) gulp.task('zip', gulp.parallel('zip:chrome', 'zip:firefox', 'zip:edge', 'zip:opera')) -// set env var for production -gulp.task('apply-prod-environment', function(done) { - process.env.NODE_ENV = 'production' - done() -}); - // high level tasks -gulp.task('dev', gulp.series('build:scss', 'dev:js', 'copy', gulp.parallel('watch:scss', 'copy:watch', 'dev:reload'))) +gulp.task('dev', + gulp.series( + 'clean', + 'dev:scss', + gulp.parallel( + 'dev:extension:js', + 'dev:mascara:js', + 'dev:copy', + 'dev:reload' + ) + ) +) + +gulp.task('dev:extension', + gulp.series( + 'clean', + 'dev:scss', + gulp.parallel( + 'dev:extension:js', + 'dev:copy', + 'dev:reload' + ) + ) +) + +gulp.task('dev:mascara', + gulp.series( + 'clean', + 'dev:scss', + gulp.parallel( + 'dev:mascara:js', + 'dev:copy', + 'dev:reload' + ) + ) +) + +gulp.task('build', + gulp.series( + 'clean', + 'build:scss', + gulpParallel( + 'build:extension:js', + 'build:mascara:js', + 'copy' + ) + ) +) + +gulp.task('build:extension', + gulp.series( + 'clean', + 'build:scss', + gulp.parallel( + 'build:extension:js', + 'copy' + ) + ) +) + +gulp.task('build:mascara', + gulp.series( + 'clean', + 'build:scss', + gulp.parallel( + 'build:mascara:js', + 'copy' + ) + ) +) -gulp.task('build', gulp.series('clean', 'build:scss', gulp.parallel('build:js', 'copy'))) -gulp.task('dist', gulp.series('apply-prod-environment', 'build', 'zip')) +gulp.task('dist', + gulp.series( + 'build', + 'zip' + ) +) // task generators -function copyTask(opts){ - var source = opts.source - var destination = opts.destination - var destinations = opts.destinations || [ destination ] - var pattern = opts.pattern || '/**/*' - - return performCopy - - function performCopy(){ - let stream = gulp.src(source + pattern, { base: source }) - destinations.forEach(function(destination) { - stream = stream.pipe(gulp.dest(destination)) - }) - stream.pipe(gulpif(debug,livereload())) - - return stream - } -} - function zipTask(target) { return () => { return gulp.src(`dist/${target}/**`) @@ -337,24 +470,48 @@ function zipTask(target) { function generateBundler(opts, performBundle) { const browserifyOpts = assign({}, watchify.args, { - entries: ['./app/scripts/'+opts.filename], + entries: [opts.filepath], plugin: 'browserify-derequire', - debug: true, - fullPaths: debug, + debug: opts.buildSourceMaps, + fullPaths: opts.buildWithFullPaths, }) let bundler = browserify(browserifyOpts) + // inject variables into bundle + bundler.transform(envify({ + METAMASK_DEBUG: opts.devMode, + NODE_ENV: opts.devMode ? 'development' : 'production', + })) + + // Minification + if (opts.minifyBuild) { + bundler.transform('uglifyify', { + global: true, + mangle: { + reserved: [ 'MetamaskInpageProvider' ] + }, + }) + } + if (opts.watch) { bundler = watchify(bundler) // on any file update, re-runs the bundler - bundler.on('update', performBundle) + bundler.on('update', async (ids) => { + const stream = performBundle() + await endOfStream(stream) + livereload.changed(`${ids}`) + }) } return bundler } function discTask(opts) { + opts = Object.assign({ + buildWithFullPaths: true, + }, opts) + const bundler = generateBundler(opts, performBundle) // output build logs to terminal bundler.on('log', gutil.log) @@ -363,9 +520,9 @@ function discTask(opts) { function performBundle(){ // start "disc" build - let discDir = path.join(__dirname, 'disc') + const discDir = path.join(__dirname, 'disc') mkdirp.sync(discDir) - let discPath = path.join(discDir, `${opts.label}.html`) + const discPath = path.join(discDir, `${opts.label}.html`) return ( bundler.bundle() @@ -384,43 +541,45 @@ function bundleTask(opts) { return performBundle function performBundle(){ - return ( - - bundler.bundle() + let buildStream = bundler.bundle() + + // handle errors + buildStream.on('error', (err) => { + beep() + if (opts.watch) { + console.warn(err.stack) + } else { + throw err + } + }) - // handle errors - .on('error', (err) => { - beep() - if (opts.watch) { - console.warn(err.stack) - } else { - throw err - } - }) + // process bundles + buildStream = buildStream // convert bundle stream to gulp vinyl stream .pipe(source(opts.filename)) - // inject variables into bundle - .pipe(replace('\'GULP_METAMASK_DEBUG\'', debug)) // buffer file contents (?) .pipe(buffer()) - // sourcemaps - // loads map from browserify file - .pipe(sourcemaps.init({ loadMaps: true })) - // Minification - .pipe(gulpif(opts.isBuild, uglify({ - mangle: { reserved: [ 'MetamaskInpageProvider' ] }, - }))) - // writes .map file - .pipe(sourcemaps.write(debug ? './' : '../../sourcemaps')) - // write completed bundles - .pipe(gulp.dest('./dist/firefox/scripts')) - .pipe(gulp.dest('./dist/chrome/scripts')) - .pipe(gulp.dest('./dist/edge/scripts')) - .pipe(gulp.dest('./dist/opera/scripts')) - // finally, trigger live reload - .pipe(gulpif(debug, livereload())) - ) + // Initialize Source Maps + if (opts.buildSourceMaps) { + buildStream = buildStream + // loads map from browserify file + .pipe(sourcemaps.init({ loadMaps: true })) + } + + // Finalize Source Maps (writes .map file) + if (opts.buildSourceMaps) { + buildStream = buildStream + .pipe(sourcemaps.write(opts.sourceMapDir)) + } + + // write completed bundles + opts.destinations.forEach((dest) => { + buildStream = buildStream.pipe(gulp.dest(dest)) + }) + + return buildStream + } } diff --git a/mascara/proxy/index.html b/mascara/proxy/index.html index b83fc41af..4e167db72 100644 --- a/mascara/proxy/index.html +++ b/mascara/proxy/index.html @@ -17,4 +17,4 @@ Hello! I am the MetaMask iframe. <script src="./proxy.js"></script> </body> -</html>
\ No newline at end of file +</html> diff --git a/mascara/server/index.js b/mascara/server/index.js index 6fb1287cc..a30120438 100644 --- a/mascara/server/index.js +++ b/mascara/server/index.js @@ -1,7 +1,5 @@ const path = require('path') const express = require('express') -const createBundle = require('./util').createBundle -const serveBundle = require('./util').serveBundle const compression = require('compression') module.exports = createMetamascaraServer @@ -9,27 +7,14 @@ module.exports = createMetamascaraServer function createMetamascaraServer () { - // start bundlers - const metamascaraBundle = createBundle(path.join(__dirname, '/../src/mascara.js')) - const proxyBundle = createBundle(path.join(__dirname, '/../src/proxy.js')) - const uiBundle = createBundle(path.join(__dirname, '/../src/ui.js')) - const backgroundBuild = createBundle(path.join(__dirname, '/../src/background.js')) - - // serve bundles + // setup server const server = express() server.use(compression()) - // ui window - serveBundle(server, '/ui.js', uiBundle) + // serve assets server.use(express.static(path.join(__dirname, '/../ui/'), { setHeaders: (res) => res.set('X-Frame-Options', 'DENY') })) - server.use(express.static(path.join(__dirname, '/../../dist/chrome'))) - // metamascara - serveBundle(server, '/metamascara.js', metamascaraBundle) - // proxy - serveBundle(server, '/proxy/proxy.js', proxyBundle) - server.use('/proxy/', express.static(path.join(__dirname, '/../proxy'))) - // background - serveBundle(server, '/background.js', backgroundBuild) + server.use(express.static(path.join(__dirname, '/../../dist/mascara'))) + server.use(express.static(path.join(__dirname, '/../proxy'))) return server diff --git a/mascara/src/app/first-time/index.js b/mascara/src/app/first-time/index.js index c0bba53d6..0cc3b4b0e 100644 --- a/mascara/src/app/first-time/index.js +++ b/mascara/src/app/first-time/index.js @@ -20,7 +20,6 @@ class FirstTimeFlow extends Component { seedWords: PropTypes.string, address: PropTypes.string, noActiveNotices: PropTypes.bool, - goToBuyEtherView: PropTypes.func.isRequired, }; static defaultProps = { @@ -171,4 +170,3 @@ export default connect( openBuyEtherModal: () => dispatch(showModal({ name: 'DEPOSIT_ETHER'})), }) )(FirstTimeFlow) - diff --git a/mascara/src/background.js b/mascara/src/background.js index 8aa1d8fe2..40a684f3d 100644 --- a/mascara/src/background.js +++ b/mascara/src/background.js @@ -30,15 +30,19 @@ global.addEventListener('activate', function (event) { log.debug('inside:open') - -// // state persistence +// state persistence const dbController = new DbController({ key: STORAGE_KEY, }) -loadStateFromPersistence() -.then((initState) => setupController(initState)) -.then(() => log.debug('MetaMask initialization complete.')) -.catch((err) => console.error('WHILE SETTING UP:', err)) + +start().catch(log.error) + +async function start() { + log.debug('MetaMask initializing...') + const initState = await loadStateFromPersistence() + await setupController(initState) + log.debug('MetaMask initialization complete.') +} // // State and Persistence diff --git a/mascara/src/mascara.js b/mascara/src/metamascara.js index 0af6f532f..0af6f532f 100644 --- a/mascara/src/mascara.js +++ b/mascara/src/metamascara.js diff --git a/mascara/src/proxy.js b/mascara/src/proxy.js index 54c5d5cf4..80b4dc516 100644 --- a/mascara/src/proxy.js +++ b/mascara/src/proxy.js @@ -1,13 +1,13 @@ const createParentStream = require('iframe-stream').ParentStream -const SWcontroller = require('client-sw-ready-event/lib/sw-client.js') +const SwController = require('sw-controller') const SwStream = require('sw-stream/lib/sw-stream.js') -const intervalDelay = Math.floor(Math.random() * (30000 - 1000)) + 1000 -const background = new SWcontroller({ - fileName: '/background.js', - letBeIdle: false, - wakeUpInterval: 30000, - intervalDelay, +const keepAliveDelay = Math.floor(Math.random() * (30000 - 1000)) + 1000 +const background = new SwController({ + fileName: './scripts/background.js', + keepAlive: true, + keepAliveInterval: 30000, + keepAliveDelay, }) const pageStream = createParentStream() diff --git a/mascara/src/ui.js b/mascara/src/ui.js index b272a2e06..f35a11fc4 100644 --- a/mascara/src/ui.js +++ b/mascara/src/ui.js @@ -1,6 +1,6 @@ const injectCss = require('inject-css') -const SWcontroller = require('client-sw-ready-event/lib/sw-client.js') -const SwStream = require('sw-stream/lib/sw-stream.js') +const SwController = require('sw-controller') +const SwStream = require('sw-stream') const MetaMaskUiCss = require('../../ui/css') const MetamascaraPlatform = require('../../app/scripts/platforms/window') const startPopup = require('../../app/scripts/popup-core') @@ -8,27 +8,44 @@ const startPopup = require('../../app/scripts/popup-core') // create platform global global.platform = new MetamascaraPlatform() - var css = MetaMaskUiCss() injectCss(css) const container = document.getElementById('app-content') -var name = 'popup' +const name = 'popup' window.METAMASK_UI_TYPE = name window.METAMASK_PLATFORM_TYPE = 'mascara' -const intervalDelay = Math.floor(Math.random() * (30000 - 1000)) + 1000 +const keepAliveDelay = Math.floor(Math.random() * (30000 - 1000)) + 1000 -const background = new SWcontroller({ - fileName: '/background.js', - letBeIdle: false, - intervalDelay, - wakeUpInterval: 20000, +const swController = new SwController({ + fileName: './background.js', + keepAlive: true, + keepAliveDelay, + keepAliveInterval: 20000, }) + +swController.once('updatefound', windowReload) +swController.once('ready', async () => { + try { + swController.removeListener('updatefound', windowReload) + console.log('swController ready') + await timeout(1000) + console.log('connecting to app') + await connectApp() + console.log('app connected') + } catch (err) { + console.error(err) + } +}) + +console.log('starting service worker') +swController.startWorker() + // Setup listener for when the service worker is read -const connectApp = function (readSw) { +function connectApp() { const connectionStream = SwStream({ - serviceWorker: background.controller, + serviceWorker: swController.getWorker(), context: name, }) return new Promise((resolve, reject) => { @@ -43,19 +60,6 @@ const connectApp = function (readSw) { }) }) } -background.on('ready', async (sw) => { - try { - background.removeListener('updatefound', connectApp) - await timeout(1000) - await connectApp(sw) - console.log('hello from cb ready event!') - } catch (e) { - console.error(e) - } -}) -background.on('updatefound', windowReload) - -background.startWorker() function windowReload () { if (window.METAMASK_SKIP_RELOAD) return diff --git a/mascara/ui/index.html b/mascara/ui/index.html index eac8e4898..dbc445891 100644 --- a/mascara/ui/index.html +++ b/mascara/ui/index.html @@ -7,6 +7,6 @@ </head> <body> <div id="app-content"></div> - <script src="./ui.js" type="text/javascript" charset="utf-8"></script> + <script src="./scripts/ui.js" type="text/javascript" charset="utf-8"></script> </body> -</html>
\ No newline at end of file +</html> diff --git a/old-ui/app/app.js b/old-ui/app/app.js index c79ac633a..37611987f 100644 --- a/old-ui/app/app.js +++ b/old-ui/app/app.js @@ -171,7 +171,7 @@ App.prototype.renderAppBar = function () { h('img', { height: 24, width: 24, - src: '/images/icon-128.png', + src: './images/icon-128.png', }), h(NetworkIndicator, { @@ -581,7 +581,6 @@ App.prototype.renderPrimary = function () { case 'qr': log.debug('rendering show qr screen') - console.log(`QrView`, QrView); return h('div', { style: { position: 'absolute', diff --git a/old-ui/app/components/buy-button-subview.js b/old-ui/app/components/buy-button-subview.js index 843627c33..56d173839 100644 --- a/old-ui/app/components/buy-button-subview.js +++ b/old-ui/app/components/buy-button-subview.js @@ -247,7 +247,6 @@ BuyButtonSubview.prototype.backButtonContext = function () { if (this.props.context === 'confTx') { this.props.dispatch(actions.showConfTxPage(false)) } else { - console.log(`actions.goHome`, actions.goHome); this.props.dispatch(actions.goHome()) } } diff --git a/old-ui/app/components/pending-tx.js b/old-ui/app/components/pending-tx.js index 720df2243..7f63d9fdf 100644 --- a/old-ui/app/components/pending-tx.js +++ b/old-ui/app/components/pending-tx.js @@ -62,8 +62,8 @@ PendingTx.prototype.render = function () { const gasBn = hexToBn(gas) // default to 8MM gas limit const gasLimit = new BN(parseInt(blockGasLimit) || '8000000') - const safeGasLimitBN = this.bnMultiplyByFraction(gasLimit, 19, 20) - const saferGasLimitBN = this.bnMultiplyByFraction(gasLimit, 18, 20) + const safeGasLimitBN = this.bnMultiplyByFraction(gasLimit, 99, 100) + const saferGasLimitBN = this.bnMultiplyByFraction(gasLimit, 98, 100) const safeGasLimit = safeGasLimitBN.toString(10) // Gas Price @@ -311,7 +311,7 @@ PendingTx.prototype.render = function () { style: { fontSize: '0.9em', }, - }, 'Gas limit set dangerously high. Approving this transaction is likely to fail.') + }, 'Gas limit set dangerously high. Approving this transaction is liable to fail.') : null, ]), diff --git a/old-ui/app/components/qr-code.js b/old-ui/app/components/qr-code.js index fa38dcd92..06b9aed9b 100644 --- a/old-ui/app/components/qr-code.js +++ b/old-ui/app/components/qr-code.js @@ -25,7 +25,6 @@ function QrCodeView () { QrCodeView.prototype.render = function () { const props = this.props const Qr = props.Qr - console.log(`QrCodeView Qr`, Qr); const address = `${isHexPrefixed(Qr.data) ? 'ethereum:' : ''}${Qr.data}` const qrImage = qrCode(4, 'M') qrImage.addData(address) diff --git a/old-ui/app/components/range-slider.js b/old-ui/app/components/range-slider.js index 823f5eb01..bae740a74 100644 --- a/old-ui/app/components/range-slider.js +++ b/old-ui/app/components/range-slider.js @@ -35,7 +35,7 @@ RangeSlider.prototype.render = function () { step: increment, style: range, value: state.value || defaultValue, - onChange: mirrorInput ? this.mirrorInputs.bind(this, event) : onInput, + onChange: mirrorInput ? this.mirrorInputs.bind(this) : onInput, }), // Mirrored input for range @@ -47,7 +47,7 @@ RangeSlider.prototype.render = function () { value: state.value || defaultValue, step: increment, style: input, - onChange: this.mirrorInputs.bind(this, event), + onChange: this.mirrorInputs.bind(this), }) : null, ]) ) diff --git a/old-ui/app/components/transaction-list-item.js b/old-ui/app/components/transaction-list-item.js index 7ab3414e5..b9f82c668 100644 --- a/old-ui/app/components/transaction-list-item.js +++ b/old-ui/app/components/transaction-list-item.js @@ -30,7 +30,12 @@ function TransactionListItem () { TransactionListItem.prototype.showRetryButton = function () { const { transaction = {}, transactions } = this.props - const { status, submittedTime, txParams } = transaction + const { submittedTime, txParams } = transaction + + if (!txParams) { + return false + } + const currentNonce = txParams.nonce const currentNonceTxs = transactions.filter(tx => tx.txParams.nonce === currentNonce) const currentNonceSubmittedTxs = currentNonceTxs.filter(tx => tx.status === 'submitted') diff --git a/old-ui/app/config.js b/old-ui/app/config.js index 9e07cf348..508770bd4 100644 --- a/old-ui/app/config.js +++ b/old-ui/app/config.js @@ -42,7 +42,7 @@ ConfigScreen.prototype.render = function () { // subtitle and nav h('.section-title.flex-row.flex-center', [ h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', { - onClick: (event) => { + onClick: () => { state.dispatch(actions.goHome()) }, }), @@ -168,7 +168,6 @@ ConfigScreen.prototype.render = function () { h('a', { href: 'http://metamask.helpscoutdocs.com/article/36-resetting-an-account', target: '_blank', - onClick (event) { this.navigateTo(event.target.href) }, }, 'Read more.'), ]), h('br'), @@ -260,7 +259,3 @@ function currentProviderDisplay (metamaskState) { h('span', value), ]) } - -ConfigScreen.prototype.navigateTo = function (url) { - global.platform.openWindow({ url }) -} diff --git a/package-lock.json b/package-lock.json index 5d1c46c26..2c1589bec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -188,7 +188,7 @@ "integrity": "sha1-AtD3eBwe5eG+WkMSoyX76LGzcjE=", "dev": true, "requires": { - "https-proxy-agent": "2.2.0", + "https-proxy-agent": "2.2.1", "node-fetch": "1.7.3", "progress": "2.0.0", "proxy-from-env": "1.0.0" @@ -213,9 +213,9 @@ } }, "https-proxy-agent": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.0.tgz", - "integrity": "sha512-uUWcfXHvy/dwfM9bqa6AozvAjS32dZSTUYd/4SEpYKRg6LEcPLshksnQYRudM9AyNvUARMfAg5TLjUDyX/K4vA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", + "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", "dev": true, "requires": { "agent-base": "4.2.0", @@ -224,6 +224,21 @@ } } }, + "@sindresorhus/is": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", + "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==", + "dev": true + }, + "@sinonjs/formatio": { + "version": "2.0.0", + "resolved": "http://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", + "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", + "dev": true, + "requires": { + "samsam": "1.3.0" + } + }, "@types/node": { "version": "8.5.5", "resolved": "https://registry.npmjs.org/@types/node/-/node-8.5.5.tgz", @@ -562,6 +577,12 @@ "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=", "dev": true }, + "any-observable": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.2.0.tgz", + "integrity": "sha1-xnhwBYADV5AJCD9UrAq6+1wz0kI=", + "dev": true + }, "any-promise": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-0.1.0.tgz", @@ -898,6 +919,65 @@ "async-done": "1.2.4" } }, + "async.queue": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/async.queue/-/async.queue-0.5.2.tgz", + "integrity": "sha1-jV2QgS4UgQZrwJBOjMFxKxfDvXw=", + "dev": true, + "requires": { + "async.util.queue": "0.5.2" + } + }, + "async.util.arrayeach": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/async.util.arrayeach/-/async.util.arrayeach-0.5.2.tgz", + "integrity": "sha1-WMTpgCjVXWm/sFrrOvROClVagpw=", + "dev": true + }, + "async.util.isarray": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/async.util.isarray/-/async.util.isarray-0.5.2.tgz", + "integrity": "sha1-5i2sjyY29lh13PdSHC0k0N+yu98=", + "dev": true + }, + "async.util.map": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/async.util.map/-/async.util.map-0.5.2.tgz", + "integrity": "sha1-5YjvhuCzq18CfZevTWg10FXKadY=", + "dev": true + }, + "async.util.noop": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/async.util.noop/-/async.util.noop-0.5.2.tgz", + "integrity": "sha1-vdYrl8sKo/YLWGrRSEaGmJdeWLk=", + "dev": true + }, + "async.util.onlyonce": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/async.util.onlyonce/-/async.util.onlyonce-0.5.2.tgz", + "integrity": "sha1-uOb8AErckjFk154y8oE+5GXCT/I=", + "dev": true + }, + "async.util.queue": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/async.util.queue/-/async.util.queue-0.5.2.tgz", + "integrity": "sha1-V/Zavho83yc9MavSirlUJfgiLuU=", + "dev": true, + "requires": { + "async.util.arrayeach": "0.5.2", + "async.util.isarray": "0.5.2", + "async.util.map": "0.5.2", + "async.util.noop": "0.5.2", + "async.util.onlyonce": "0.5.2", + "async.util.setimmediate": "0.5.2" + } + }, + "async.util.setimmediate": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/async.util.setimmediate/-/async.util.setimmediate-0.5.2.tgz", + "integrity": "sha1-KBLrq/KlgCd1jUvHeT0cz68QJV8=", + "dev": true + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -2807,6 +2887,29 @@ } } }, + "cacheable-request": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz", + "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=", + "dev": true, + "requires": { + "clone-response": "1.0.2", + "get-stream": "3.0.0", + "http-cache-semantics": "3.8.1", + "keyv": "3.0.0", + "lowercase-keys": "1.0.0", + "normalize-url": "2.0.1", + "responselike": "1.0.2" + }, + "dependencies": { + "lowercase-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", + "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=", + "dev": true + } + } + }, "cached-path-relative": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.1.tgz", @@ -2994,6 +3097,19 @@ "readdirp": "2.1.0" } }, + "chromedriver": { + "version": "2.36.0", + "resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-2.36.0.tgz", + "integrity": "sha512-Lq2HrigCJ4RVdIdCmchenv1rVrejNSJ7EUCQojycQo12ww3FedQx4nb+GgTdqMhjbOMTqq5+ziaiZlrEN2z1gQ==", + "dev": true, + "requires": { + "del": "3.0.0", + "extract-zip": "1.6.6", + "kew": "0.7.0", + "mkdirp": "0.5.1", + "request": "2.83.0" + } + }, "cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", @@ -3090,6 +3206,16 @@ "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.2.5.tgz", "integrity": "sha1-+zgB1FNGdknvNgPH1hoCvRKb3m0=" }, + "cli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", + "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", + "dev": true, + "requires": { + "exit": "0.1.2", + "glob": "7.1.2" + } + }, "cli-cursor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", @@ -3098,16 +3224,52 @@ "restore-cursor": "2.0.0" } }, + "cli-spinners": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-0.1.2.tgz", + "integrity": "sha1-u3ZNiOGF+54eaiofGXcjGPYF4xw=", + "dev": true + }, + "cli-table": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", + "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=", + "dev": true, + "requires": { + "colors": "1.0.3" + }, + "dependencies": { + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true + } + } + }, + "cli-truncate": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", + "integrity": "sha1-nxXPuwcFAFNpIWxiasfQWrkN1XQ=", + "dev": true, + "requires": { + "slice-ansi": "0.0.4", + "string-width": "1.0.2" + }, + "dependencies": { + "slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", + "dev": true + } + } + }, "cli-width": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" }, - "client-sw-ready-event": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/client-sw-ready-event/-/client-sw-ready-event-3.4.0.tgz", - "integrity": "sha1-/0hkYXaQVed0hXDxrvECuGdbZtA=" - }, "cliui": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", @@ -3138,6 +3300,15 @@ "is-supported-regexp-flag": "1.0.0" } }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "1.0.0" + } + }, "clone-stats": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", @@ -3935,6 +4106,12 @@ "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", "integrity": "sha1-vEZ0gAQ3iyGjYMn8fPUjF5B2L7g=" }, + "dargs": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dargs/-/dargs-5.1.0.tgz", + "integrity": "sha1-7H6lDHhWTNNsnV7Bj2Yyn63ieCk=", + "dev": true + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -3950,6 +4127,12 @@ "dev": true, "optional": true }, + "date-fns": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.29.0.tgz", + "integrity": "sha512-lbTXWZ6M20cWH8N9S6afb0SBm6tMk+uUg6z3MqHPKE9atmsY3kJkTm8vKe93izJ2B2+q5MV990sM2CHgtAZaOw==", + "dev": true + }, "date-format": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/date-format/-/date-format-1.2.0.tgz", @@ -4021,6 +4204,15 @@ "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "1.0.0" + } + }, "deep-diff": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/deep-diff/-/deep-diff-0.3.8.tgz", @@ -4229,6 +4421,12 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "detect-conflict": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/detect-conflict/-/detect-conflict-1.0.1.tgz", + "integrity": "sha1-CIZXpmqWHAUBnbfEIwiDsca0F24=", + "dev": true + }, "detect-file": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", @@ -4607,6 +4805,12 @@ } } }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, "duplexify": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.1.tgz", @@ -4636,6 +4840,12 @@ "jsbn": "0.1.1" } }, + "editions": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz", + "integrity": "sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg==", + "dev": true + }, "editorconfig": { "version": "0.13.3", "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.13.3.tgz", @@ -4665,6 +4875,12 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "ejs": { + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.8.tgz", + "integrity": "sha512-QIDZL54fyV8MDcAsO91BMH1ft2qGGaHIJsJIA/+t+7uvXol1dm413fPcUgUb4k8F/9457rx4/KFE4XfDifrQxQ==", + "dev": true + }, "electron-releases": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/electron-releases/-/electron-releases-2.1.0.tgz", @@ -4678,6 +4894,12 @@ "electron-releases": "2.1.0" } }, + "elegant-spinner": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", + "integrity": "sha1-2wQ1IcldfjA/2PNFvtwzSc+wcp4=", + "dev": true + }, "elliptic": { "version": "6.4.0", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", @@ -4912,6 +5134,16 @@ "prr": "1.0.1" } }, + "error": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/error/-/error-7.0.2.tgz", + "integrity": "sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI=", + "dev": true, + "requires": { + "string-template": "0.2.1", + "xtend": "4.0.1" + } + }, "error-ex": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", @@ -5188,13 +5420,30 @@ "integrity": "sha1-mh3qWLM1wxJCIZ0Fmzf/sUMJ9uE=", "dev": true }, + "eslint-plugin-json": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-json/-/eslint-plugin-json-1.2.0.tgz", + "integrity": "sha1-m6c7sL6Z1QCT6In1uWhGPSow764=", + "dev": true, + "requires": { + "jshint": "2.9.5" + } + }, "eslint-plugin-mocha": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-4.11.0.tgz", - "integrity": "sha1-kRk6L1XiCl41l0BUoAidMBmO5Xg=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-5.0.0.tgz", + "integrity": "sha512-mpRWWsjxRco2bY4qE5DL8SmGoVF0Onb6DZrbgOjFoNo1YNN299K2voIozd8Kce3qC/neWNr2XF27E1ZDMl1yZg==", "dev": true, "requires": { - "ramda": "0.24.1" + "ramda": "0.25.0" + }, + "dependencies": { + "ramda": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.25.0.tgz", + "integrity": "sha512-GXpfrYVPwx3K7RQ6aYT8KPS8XViSXUVJT1ONhoKPE9VAleW42YE+U+8VEyGWt41EnEQW7gwecYJriTI0pKoecQ==", + "dev": true + } } }, "eslint-plugin-react": { @@ -5339,6 +5588,11 @@ "json-rpc-error": "2.0.0", "promise-to-callback": "1.0.0" } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" } } }, @@ -5652,6 +5906,13 @@ "ethjs-util": "0.1.4", "pify": "2.3.0", "tape": "4.8.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } } }, "ethjs-format": { @@ -5710,7 +5971,7 @@ "ethereumjs-vm": "2.3.2", "through2": "2.0.3", "treeify": "1.1.0", - "web3-provider-engine": "13.6.0" + "web3-provider-engine": "13.8.0" } }, "ethereum-common": { @@ -6065,12 +6326,12 @@ } }, "ethjs-query": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/ethjs-query/-/ethjs-query-0.3.2.tgz", - "integrity": "sha1-9IikjOGZTNTHfsy3tSkCxvKc/YU=", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/ethjs-query/-/ethjs-query-0.3.4.tgz", + "integrity": "sha512-RkeLtBwuXJkBIf/U+Az0GOT203UiBLmN7WA6WZIwSTbmhH2yNicggwaWKvN3TOtpErOsXnzYTZp82mElHdORUQ==", "requires": { - "ethjs-format": "0.2.4", - "ethjs-rpc": "0.1.8" + "ethjs-format": "0.2.5", + "ethjs-rpc": "0.1.9" }, "dependencies": { "bn.js": { @@ -6079,12 +6340,12 @@ "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" }, "ethjs-format": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/ethjs-format/-/ethjs-format-0.2.4.tgz", - "integrity": "sha1-W7vESlrSTmirOTMS/5A5pztlv4E=", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/ethjs-format/-/ethjs-format-0.2.5.tgz", + "integrity": "sha1-RPMKvuF7B01xYtLIhqv/0GWCiSU=", "requires": { "bn.js": "4.11.6", - "ethjs-schema": "0.1.9", + "ethjs-schema": "0.2.0", "ethjs-util": "0.1.3", "is-hex-prefixed": "1.0.0", "number-to-bn": "1.7.0", @@ -6092,9 +6353,14 @@ } }, "ethjs-rpc": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/ethjs-rpc/-/ethjs-rpc-0.1.8.tgz", - "integrity": "sha1-FnZ0DkHHIoGWpxGJ0z8VychbWZ0=" + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/ethjs-rpc/-/ethjs-rpc-0.1.9.tgz", + "integrity": "sha512-KJqT7cgTeCJQ2RY1AlVmTZVnKIUXMPg+niPN5VJKwRSzpjgfr3LTVHlGbkRCqZtOMDi0ogB2vHZaRQiZBXZTUg==" + }, + "ethjs-schema": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/ethjs-schema/-/ethjs-schema-0.2.0.tgz", + "integrity": "sha1-B7RtT1W3kqhGyQp58zDTHREsyjg=" }, "ethjs-util": { "version": "0.1.3", @@ -6227,6 +6493,18 @@ "integrity": "sha1-BmDjUlouidnkRhKUQMJy7foktSk=", "dev": true }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "exit-hook": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", + "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", + "dev": true + }, "expand-braces": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz", @@ -6382,6 +6660,35 @@ "is-extglob": "1.0.0" } }, + "extract-zip": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.6.tgz", + "integrity": "sha1-EpDt6NINCHK0Kf0/NRyhKOxe+Fw=", + "dev": true, + "requires": { + "concat-stream": "1.6.0", + "debug": "2.6.9", + "mkdirp": "0.5.0", + "yauzl": "2.4.1" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", + "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + } + } + }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -6490,6 +6797,15 @@ } } }, + "fd-slicer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", + "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "dev": true, + "requires": { + "pend": "1.2.0" + } + }, "fetch-ponyfill": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz", @@ -6589,6 +6905,12 @@ "which": "1.3.0" } }, + "find-index": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz", + "integrity": "sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ=", + "dev": true + }, "find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", @@ -7002,6 +7324,13 @@ "pify": "2.3.0", "pinkie-promise": "2.0.1", "rimraf": "2.6.2" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } } } } @@ -7011,6 +7340,12 @@ "resolved": "https://registry.npmjs.org/flatten/-/flatten-0.0.1.tgz", "integrity": "sha1-VURAdm2goNYDmZ9DNFP2wvxqdcE=" }, + "flow-parser": { + "version": "0.69.0", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.69.0.tgz", + "integrity": "sha1-N4tRKNbQtVSosvFqTKPhq5ZJ8A4=", + "dev": true + }, "flush-write-stream": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.2.tgz", @@ -7061,12 +7396,6 @@ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" }, - "fork-stream": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/fork-stream/-/fork-stream-0.0.4.tgz", - "integrity": "sha1-24Sfznf2cIpfjzhq5TOgkHtUrnA=", - "dev": true - }, "form-data": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", @@ -7110,6 +7439,16 @@ "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", "dev": true }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3" + } + }, "fs-access": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz", @@ -7193,12 +7532,14 @@ "dependencies": { "abbrev": { "version": "1.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", + "integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8=", "optional": true }, "ajv": { "version": "4.11.8", - "bundled": true, + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", "optional": true, "requires": { "co": "4.6.0", @@ -7207,16 +7548,19 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "aproba": { "version": "1.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.1.1.tgz", + "integrity": "sha1-ldNgDwdxCqDpKYxyatXs8urLq6s=", "optional": true }, "are-we-there-yet": { "version": "1.1.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", + "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "optional": true, "requires": { "delegates": "1.0.0", @@ -7225,36 +7569,43 @@ }, "asn1": { "version": "0.2.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", "optional": true }, "assert-plus": { "version": "0.2.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", "optional": true }, "asynckit": { "version": "0.4.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "optional": true }, "aws-sign2": { "version": "0.6.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", "optional": true }, "aws4": { "version": "1.6.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", "optional": true }, "balanced-match": { "version": "0.4.2", - "bundled": true + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=" }, "bcrypt-pbkdf": { "version": "1.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", "optional": true, "requires": { "tweetnacl": "0.14.5" @@ -7262,21 +7613,24 @@ }, "block-stream": { "version": "0.0.9", - "bundled": true, + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", "requires": { "inherits": "2.0.3" } }, "boom": { "version": "2.10.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", "requires": { "hoek": "2.16.3" } }, "brace-expansion": { "version": "1.1.7", - "bundled": true, + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz", + "integrity": "sha1-Pv/DxQ4ABTH7cg6v+A8K6O8jz1k=", "requires": { "balanced-match": "0.4.2", "concat-map": "0.0.1" @@ -7284,51 +7638,61 @@ }, "buffer-shims": { "version": "1.0.0", - "bundled": true + "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", + "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=" }, "caseless": { "version": "0.12.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "optional": true }, "co": { "version": "4.6.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", "optional": true }, "code-point-at": { "version": "1.1.0", - "bundled": true + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "combined-stream": { "version": "1.0.5", - "bundled": true, + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", "requires": { "delayed-stream": "1.0.0" } }, "concat-map": { "version": "0.0.1", - "bundled": true + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, "core-util-is": { "version": "1.0.2", - "bundled": true + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "cryptiles": { "version": "2.0.5", - "bundled": true, + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", "requires": { "boom": "2.10.1" } }, "dashdash": { "version": "1.14.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "optional": true, "requires": { "assert-plus": "1.0.0" @@ -7336,14 +7700,16 @@ "dependencies": { "assert-plus": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "optional": true } } }, "debug": { "version": "2.6.8", - "bundled": true, + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", "optional": true, "requires": { "ms": "2.0.0" @@ -7351,26 +7717,31 @@ }, "deep-extend": { "version": "0.4.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", + "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=", "optional": true }, "delayed-stream": { "version": "1.0.0", - "bundled": true + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, "delegates": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", "optional": true }, "detect-libc": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.2.tgz", + "integrity": "sha1-ca1dIEvxempsqPRQxhRUBm70YeE=", "optional": true }, "ecc-jsbn": { "version": "0.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", "optional": true, "requires": { "jsbn": "0.1.1" @@ -7378,21 +7749,25 @@ }, "extend": { "version": "3.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", "optional": true }, "extsprintf": { "version": "1.0.2", - "bundled": true + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", + "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=" }, "forever-agent": { "version": "0.6.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", "optional": true }, "form-data": { "version": "2.1.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", "optional": true, "requires": { "asynckit": "0.4.0", @@ -7402,11 +7777,13 @@ }, "fs.realpath": { "version": "1.0.0", - "bundled": true + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "fstream": { "version": "1.0.11", - "bundled": true, + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", + "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", "requires": { "graceful-fs": "4.1.11", "inherits": "2.0.3", @@ -7416,7 +7793,8 @@ }, "fstream-ignore": { "version": "1.0.5", - "bundled": true, + "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz", + "integrity": "sha1-nDHa40dnAY/h0kmyTa2mfQktoQU=", "optional": true, "requires": { "fstream": "1.0.11", @@ -7426,7 +7804,8 @@ }, "gauge": { "version": "2.7.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "optional": true, "requires": { "aproba": "1.1.1", @@ -7441,7 +7820,8 @@ }, "getpass": { "version": "0.1.7", - "bundled": true, + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "optional": true, "requires": { "assert-plus": "1.0.0" @@ -7449,14 +7829,16 @@ "dependencies": { "assert-plus": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "optional": true } } }, "glob": { "version": "7.1.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "requires": { "fs.realpath": "1.0.0", "inflight": "1.0.6", @@ -7468,16 +7850,19 @@ }, "graceful-fs": { "version": "4.1.11", - "bundled": true + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" }, "har-schema": { "version": "1.0.5", - "bundled": true, + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", + "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", "optional": true }, "har-validator": { "version": "4.2.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", + "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", "optional": true, "requires": { "ajv": "4.11.8", @@ -7486,12 +7871,14 @@ }, "has-unicode": { "version": "2.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "optional": true }, "hawk": { "version": "3.1.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", "requires": { "boom": "2.10.1", "cryptiles": "2.0.5", @@ -7501,11 +7888,13 @@ }, "hoek": { "version": "2.16.3", - "bundled": true + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" }, "http-signature": { "version": "1.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", "optional": true, "requires": { "assert-plus": "0.2.0", @@ -7515,7 +7904,8 @@ }, "inflight": { "version": "1.0.6", - "bundled": true, + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "requires": { "once": "1.4.0", "wrappy": "1.0.2" @@ -7523,37 +7913,44 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, "ini": { "version": "1.3.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", + "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=", "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { "number-is-nan": "1.0.1" } }, "is-typedarray": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "optional": true }, "isarray": { "version": "1.0.0", - "bundled": true + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "isstream": { "version": "0.1.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "optional": true }, "jodid25519": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz", + "integrity": "sha1-BtSRIlUJNBlHfUJWM2BuDpB4KWc=", "optional": true, "requires": { "jsbn": "0.1.1" @@ -7561,17 +7958,20 @@ }, "jsbn": { "version": "0.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "optional": true }, "json-schema": { "version": "0.2.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", "optional": true }, "json-stable-stringify": { "version": "1.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", "optional": true, "requires": { "jsonify": "0.0.0" @@ -7579,17 +7979,20 @@ }, "json-stringify-safe": { "version": "5.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "optional": true }, "jsonify": { "version": "0.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", "optional": true }, "jsprim": { "version": "1.4.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz", + "integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=", "optional": true, "requires": { "assert-plus": "1.0.0", @@ -7600,48 +8003,56 @@ "dependencies": { "assert-plus": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "optional": true } } }, "mime-db": { "version": "1.27.0", - "bundled": true + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz", + "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=" }, "mime-types": { "version": "2.1.15", - "bundled": true, + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz", + "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=", "requires": { "mime-db": "1.27.0" } }, "minimatch": { "version": "3.0.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { "brace-expansion": "1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" }, "mkdirp": { "version": "0.5.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "requires": { "minimist": "0.0.8" } }, "ms": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "optional": true }, "node-pre-gyp": { "version": "0.6.39", - "bundled": true, + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz", + "integrity": "sha512-OsJV74qxnvz/AMGgcfZoDaeDXKD3oY3QVIbBmwszTFkRisTSXbMQyn4UWzUMOtA5SVhrBZOTp0wcoSBgfMfMmQ==", "optional": true, "requires": { "detect-libc": "1.0.2", @@ -7659,7 +8070,8 @@ }, "nopt": { "version": "4.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "optional": true, "requires": { "abbrev": "1.1.0", @@ -7668,7 +8080,8 @@ }, "npmlog": { "version": "4.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.0.tgz", + "integrity": "sha512-ocolIkZYZt8UveuiDS0yAkkIjid1o7lPG8cYm05yNYzBn8ykQtaiPMEGp8fY9tKdDgm8okpdKzkvu1y9hUYugA==", "optional": true, "requires": { "are-we-there-yet": "1.1.4", @@ -7679,38 +8092,45 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "oauth-sign": { "version": "0.8.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", "optional": true }, "object-assign": { "version": "4.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "optional": true }, "once": { "version": "1.4.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { "wrappy": "1.0.2" } }, "os-homedir": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "optional": true }, "os-tmpdir": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "optional": true }, "osenv": { "version": "0.1.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz", + "integrity": "sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=", "optional": true, "requires": { "os-homedir": "1.0.2", @@ -7719,30 +8139,36 @@ }, "path-is-absolute": { "version": "1.0.1", - "bundled": true + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "performance-now": { "version": "0.2.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", + "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", "optional": true }, "process-nextick-args": { "version": "1.0.7", - "bundled": true + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" }, "punycode": { "version": "1.4.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", "optional": true }, "qs": { "version": "6.4.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", "optional": true }, "rc": { "version": "1.2.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.1.tgz", + "integrity": "sha1-LgPo5C7kULjLPc5lvhv4l04d/ZU=", "optional": true, "requires": { "deep-extend": "0.4.2", @@ -7753,14 +8179,16 @@ "dependencies": { "minimist": { "version": "1.2.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "optional": true } } }, "readable-stream": { "version": "2.2.9", - "bundled": true, + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz", + "integrity": "sha1-z3jsb0ptHrQ9JkiMrJfwQudLf8g=", "requires": { "buffer-shims": "1.0.0", "core-util-is": "1.0.2", @@ -7773,7 +8201,8 @@ }, "request": { "version": "2.81.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", + "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", "optional": true, "requires": { "aws-sign2": "0.6.0", @@ -7802,40 +8231,47 @@ }, "rimraf": { "version": "2.6.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", + "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", "requires": { "glob": "7.1.2" } }, "safe-buffer": { "version": "5.0.1", - "bundled": true + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz", + "integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c=" }, "semver": { "version": "5.3.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", "optional": true }, "set-blocking": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "optional": true }, "signal-exit": { "version": "3.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "optional": true }, "sntp": { "version": "1.0.9", - "bundled": true, + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", "requires": { "hoek": "2.16.3" } }, "sshpk": { "version": "1.13.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.0.tgz", + "integrity": "sha1-/yo+T9BEl1Vf7Zezmg/YL6+zozw=", "optional": true, "requires": { "asn1": "0.2.3", @@ -7851,14 +8287,16 @@ "dependencies": { "assert-plus": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", "optional": true } } }, "string-width": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { "code-point-at": "1.1.0", "is-fullwidth-code-point": "1.0.0", @@ -7867,31 +8305,36 @@ }, "string_decoder": { "version": "1.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.1.tgz", + "integrity": "sha1-YuIA8DmVWmgQ2N8KM//A8BNmLZg=", "requires": { "safe-buffer": "5.0.1" } }, "stringstream": { "version": "0.0.5", - "bundled": true, + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", "optional": true }, "strip-ansi": { "version": "3.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "2.1.1" } }, "strip-json-comments": { "version": "2.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "optional": true }, "tar": { "version": "2.2.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", "requires": { "block-stream": "0.0.9", "fstream": "1.0.11", @@ -7900,7 +8343,8 @@ }, "tar-pack": { "version": "3.4.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/tar-pack/-/tar-pack-3.4.0.tgz", + "integrity": "sha1-I74tf2cagzk3bL2wuP4/3r8xeYQ=", "optional": true, "requires": { "debug": "2.6.8", @@ -7915,7 +8359,8 @@ }, "tough-cookie": { "version": "2.3.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", + "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", "optional": true, "requires": { "punycode": "1.4.1" @@ -7923,7 +8368,8 @@ }, "tunnel-agent": { "version": "0.6.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "optional": true, "requires": { "safe-buffer": "5.0.1" @@ -7931,26 +8377,31 @@ }, "tweetnacl": { "version": "0.14.5", - "bundled": true, + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "optional": true }, "uid-number": { "version": "0.0.6", - "bundled": true, + "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", + "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=", "optional": true }, "util-deprecate": { "version": "1.0.2", - "bundled": true + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "uuid": { "version": "3.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz", + "integrity": "sha1-ZUS7ot/ajBzxfmKaOjBeK7H+5sE=", "optional": true }, "verror": { "version": "1.3.6", - "bundled": true, + "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", + "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=", "optional": true, "requires": { "extsprintf": "1.0.2" @@ -7958,7 +8409,8 @@ }, "wide-align": { "version": "1.1.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", + "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", "optional": true, "requires": { "string-width": "1.0.2" @@ -7966,7 +8418,8 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" } } }, @@ -8047,6 +8500,33 @@ "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.2.0.tgz", "integrity": "sha1-8ESOgGmFW/Kj5oPNwdMg5+KgfvQ=" }, + "ganache-cli": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ganache-cli/-/ganache-cli-6.1.0.tgz", + "integrity": "sha512-FdTeyk4uLRHGeFiMe+Qnh4Hc5KiTVqvRVVvLDFJEVVKC1P1yHhEgZeh9sp1KhuvxSrxToxgJS25UapYQwH4zHw==", + "dev": true, + "requires": { + "source-map-support": "0.5.4", + "webpack-cli": "2.0.13" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.4.tgz", + "integrity": "sha512-PETSPG6BjY1AHs2t64vS2aqAgu6dMIMXJULWFBGbh2Gr8nVLbCFDo6i/RMMvviIQ2h1Z8+5gQhVKSn2je9nmdg==", + "dev": true, + "requires": { + "source-map": "0.6.1" + } + } + } + }, "gather-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/gather-stream/-/gather-stream-1.0.0.tgz", @@ -8100,6 +8580,11 @@ "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", "dev": true }, + "get-own-enumerable-property-symbols": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-2.0.1.tgz", + "integrity": "sha512-TtY/sbOemiMKPRUDDanGCSgBYe7Mf0vbRsWnBZ+9yghpZ1MvcpSpuZFjHdEeY/LZjZy0vdLjS77L6HosisFiug==" + }, "get-stdin": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-3.0.2.tgz", @@ -8140,6 +8625,85 @@ "assert-plus": "1.0.0" } }, + "gh-got": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gh-got/-/gh-got-6.0.0.tgz", + "integrity": "sha512-F/mS+fsWQMo1zfgG9MD8KWvTWPPzzhuVwY++fhQ5Ggd+0P+CAMHtzMZhNxG+TqGfHDChJKsbh6otfMGqO2AKBw==", + "dev": true, + "requires": { + "got": "7.1.0", + "is-plain-obj": "1.1.0" + }, + "dependencies": { + "got": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/got/-/got-7.1.0.tgz", + "integrity": "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw==", + "dev": true, + "requires": { + "decompress-response": "3.3.0", + "duplexer3": "0.1.4", + "get-stream": "3.0.0", + "is-plain-obj": "1.1.0", + "is-retry-allowed": "1.1.0", + "is-stream": "1.1.0", + "isurl": "1.0.0", + "lowercase-keys": "1.0.1", + "p-cancelable": "0.3.0", + "p-timeout": "1.2.1", + "safe-buffer": "5.1.1", + "timed-out": "4.0.1", + "url-parse-lax": "1.0.0", + "url-to-options": "1.0.1" + } + }, + "p-cancelable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz", + "integrity": "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw==", + "dev": true + }, + "p-timeout": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", + "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", + "dev": true, + "requires": { + "p-finally": "1.0.0" + } + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "dev": true, + "requires": { + "prepend-http": "1.0.4" + } + } + } + }, + "gifencoder": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/gifencoder/-/gifencoder-1.1.0.tgz", + "integrity": "sha512-MVh++nximxsp8NaNRfS1+MmCviZ4wi7HhuvX8eHrfNn//1mqi8Eb03tKs6Z+lIIcSEySJ6PmS1VPZ+HdtEMlfg==", + "dev": true + }, + "github-username": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/github-username/-/github-username-4.1.0.tgz", + "integrity": "sha1-y+KABBiDIG2kISrp5LXxacML9Bc=", + "dev": true, + "requires": { + "gh-got": "6.0.0" + } + }, "gl-mat4": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/gl-mat4/-/gl-mat4-1.1.4.tgz", @@ -8259,6 +8823,15 @@ "object.defaults": "1.1.0" } }, + "glob2base": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", + "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=", + "dev": true, + "requires": { + "find-index": "0.1.1" + } + }, "global": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz", @@ -8306,6 +8879,13 @@ "object-assign": "4.1.1", "pify": "2.3.0", "pinkie-promise": "2.0.1" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } } }, "globjoin": { @@ -8332,6 +8912,31 @@ "sparkles": "1.0.0" } }, + "got": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/got/-/got-8.3.0.tgz", + "integrity": "sha512-kBNy/S2CGwrYgDSec5KTWGKUvupwkkTVAjIsVFF2shXO13xpZdFP4d4kxa//CLX2tN/rV0aYwK8vY6UKWGn2vQ==", + "dev": true, + "requires": { + "@sindresorhus/is": "0.7.0", + "cacheable-request": "2.1.4", + "decompress-response": "3.3.0", + "duplexer3": "0.1.4", + "get-stream": "3.0.0", + "into-stream": "3.1.0", + "is-retry-allowed": "1.1.0", + "isurl": "1.0.0", + "lowercase-keys": "1.0.1", + "mimic-response": "1.0.0", + "p-cancelable": "0.4.1", + "p-timeout": "2.0.1", + "pify": "3.0.0", + "safe-buffer": "5.1.1", + "timed-out": "4.0.1", + "url-parse-lax": "3.0.0", + "url-to-options": "1.0.1" + } + }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", @@ -8343,6 +8948,15 @@ "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", "dev": true }, + "grouped-queue": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/grouped-queue/-/grouped-queue-0.3.3.tgz", + "integrity": "sha1-wWfSpTGcWg4JZO9qJbfC34mWyFw=", + "dev": true, + "requires": { + "lodash": "4.17.4" + } + }, "growl": { "version": "1.10.3", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz", @@ -8529,6 +9143,52 @@ } } }, + "gulp-debug": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/gulp-debug/-/gulp-debug-3.2.0.tgz", + "integrity": "sha512-2LZzP+ydczqz1rhqq/NYxvVvYTmOa0IgBl2B1sQTdkQgku9ayOUM/KHuGPjF4QA5aO1VcG+Sskw7iCcRUqHKkA==", + "requires": { + "chalk": "2.3.2", + "fancy-log": "1.3.2", + "plur": "2.1.2", + "stringify-object": "3.2.2", + "through2": "2.0.3", + "tildify": "1.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "1.9.1" + } + }, + "chalk": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", + "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.3.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "supports-color": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", + "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "requires": { + "has-flag": "3.0.0" + } + } + } + }, "gulp-eslint": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-4.0.0.tgz", @@ -8538,17 +9198,6 @@ "gulp-util": "3.0.8" } }, - "gulp-if": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/gulp-if/-/gulp-if-2.0.2.tgz", - "integrity": "sha1-pJe351cwBQQcqivIt92jyARE1ik=", - "dev": true, - "requires": { - "gulp-match": "1.0.3", - "ternary-stream": "2.0.1", - "through2": "2.0.3" - } - }, "gulp-json-editor": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/gulp-json-editor/-/gulp-json-editor-2.2.1.tgz", @@ -8700,13 +9349,13 @@ } } }, - "gulp-match": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/gulp-match/-/gulp-match-1.0.3.tgz", - "integrity": "sha1-kcfA1/Kb7NZgbVfYCn+Hdqh6uo4=", + "gulp-multi-process": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/gulp-multi-process/-/gulp-multi-process-1.3.1.tgz", + "integrity": "sha512-okxYy3mxUkekM0RNjkBg8OPuzpnD2yXMAdnGOaQPSJ2wzBdE9R9pkTV+tzPZ65ORK7b57YUc6s+gROA4+EIOLg==", "dev": true, "requires": { - "minimatch": "3.0.4" + "async.queue": "0.5.2" } }, "gulp-replace": { @@ -9105,7 +9754,7 @@ "dev": true, "requires": { "anymatch": "1.3.2", - "chokidar": "2.0.1", + "chokidar": "2.0.3", "glob-parent": "3.1.0", "gulp-util": "3.0.8", "object-assign": "4.1.1", @@ -9129,9 +9778,9 @@ "dev": true }, "braces": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.0.tgz", - "integrity": "sha512-P4O8UQRdGiMLWSizsApmXVQDBS6KCt7dSexgLKBmH5Hr1CZq7vsnscFh8oR1sP1ab1Zj0uCHCEzZeV6SfUf3rA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.1.tgz", + "integrity": "sha512-SO5lYHA3vO6gz66erVvedSCkp7AKWdv6VcQ2N4ysXfPxdAlxAMMAdwegGGcv1Bqwm7naF1hNdk5d6AAIEHV2nQ==", "dev": true, "requires": { "arr-flatten": "1.1.0", @@ -9140,22 +9789,43 @@ "extend-shallow": "2.0.1", "fill-range": "4.0.0", "isobject": "3.0.1", + "kind-of": "6.0.2", "repeat-element": "1.1.2", "snapdragon": "0.8.1", "snapdragon-node": "2.1.1", "split-string": "3.1.0", - "to-regex": "3.0.1" + "to-regex": "3.0.2" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "1.0.2" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } } }, "chokidar": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.1.tgz", - "integrity": "sha512-rv5iP8ENhpqvDWr677rAXcB+SMoPQ1urd4ch79+PhM4lQwbATdJUQK69t0lJIKNB+VXpqxt5V1gvqs59XEPKnw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz", + "integrity": "sha512-zW8iXYZtXMx4kux/nuZVXjkLP+CyIK5Al5FHnj1OgTKGZfp4Oy6/ymtMSKFv3GD8DviEmUPmJg9eFdJ/JzudMg==", "dev": true, "requires": { "anymatch": "2.0.0", "async-each": "1.0.1", - "braces": "2.3.0", + "braces": "2.3.1", "fsevents": "1.1.3", "glob-parent": "3.1.0", "inherits": "2.0.3", @@ -9164,7 +9834,7 @@ "normalize-path": "2.1.1", "path-is-absolute": "1.0.1", "readdirp": "2.1.0", - "upath": "1.0.0" + "upath": "1.0.4" }, "dependencies": { "anymatch": { @@ -9173,12 +9843,22 @@ "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", "dev": true, "requires": { - "micromatch": "3.1.5", + "micromatch": "3.1.10", "normalize-path": "2.1.1" } } } }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "1.0.2", + "isobject": "3.0.1" + } + }, "expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", @@ -9191,7 +9871,7 @@ "posix-character-classes": "0.1.1", "regex-not": "1.0.0", "snapdragon": "0.8.1", - "to-regex": "3.0.1" + "to-regex": "3.0.2" }, "dependencies": { "define-property": { @@ -9202,6 +9882,53 @@ "requires": { "is-descriptor": "0.1.6" } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "0.1.6", + "is-data-descriptor": "0.1.4", + "kind-of": "5.1.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "2.0.4" + } } } }, @@ -9218,7 +9945,27 @@ "fragment-cache": "0.2.1", "regex-not": "1.0.0", "snapdragon": "0.8.1", - "to-regex": "3.0.1" + "to-regex": "3.0.2" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "1.0.2" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } } }, "fill-range": { @@ -9231,6 +9978,17 @@ "is-number": "3.0.0", "repeat-string": "1.6.1", "to-regex-range": "2.1.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "0.1.1" + } + } } }, "glob-parent": { @@ -9294,25 +10052,6 @@ } } }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "0.1.6", - "is-data-descriptor": "0.1.4", - "kind-of": "5.1.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -9361,24 +10100,48 @@ "dev": true }, "micromatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.5.tgz", - "integrity": "sha512-ykttrLPQrz1PUJcXjwsTUjGoPJ64StIGNE2lGVD1c9CuguJ+L7/navsE8IcDNndOoCMvYV0qc/exfVbMHkUhvA==", + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", "dev": true, "requires": { "arr-diff": "4.0.0", "array-unique": "0.3.2", - "braces": "2.3.0", - "define-property": "1.0.0", - "extend-shallow": "2.0.1", + "braces": "2.3.1", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", "extglob": "2.0.4", "fragment-cache": "0.2.1", "kind-of": "6.0.2", - "nanomatch": "1.2.7", + "nanomatch": "1.2.9", "object.pick": "1.3.0", "regex-not": "1.0.0", "snapdragon": "0.8.1", - "to-regex": "3.0.1" + "to-regex": "3.0.2" + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "2.0.2", + "extend-shallow": "3.0.2", + "regex-not": "1.0.2", + "safe-regex": "1.1.0" + }, + "dependencies": { + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "3.0.2", + "safe-regex": "1.1.0" + } + } } } } @@ -9468,6 +10231,12 @@ } } }, + "has-color": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", + "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=", + "dev": true + }, "has-cors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", @@ -9487,11 +10256,26 @@ "sparkles": "1.0.0" } }, + "has-symbol-support-x": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", + "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", + "dev": true + }, "has-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" }, + "has-to-string-tag-x": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", + "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", + "dev": true, + "requires": { + "has-symbol-support-x": "1.4.2" + } + }, "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", @@ -9814,6 +10598,12 @@ "readable-stream": "2.3.3" } }, + "http-cache-semantics": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", + "dev": true + }, "http-errors": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", @@ -10005,6 +10795,12 @@ "integrity": "sha1-rI9DbyI5td+2bV8NOpBKh6xnzF4=", "dev": true }, + "image-size": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.6.2.tgz", + "integrity": "sha512-pH3vDzpczdsKHdZ9xxR3O46unSjisgVx0IImay7Zz2EdhRVbCkj+nthx9OuuWEhakx9FAO+fNVGrF0rZ2oMOvw==", + "dev": true + }, "immediate": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.2.3.tgz", @@ -10247,6 +11043,16 @@ "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=" }, + "into-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", + "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", + "dev": true, + "requires": { + "from2": "2.3.0", + "p-is-promise": "1.1.0" + } + }, "invariant": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", @@ -10275,8 +11081,7 @@ "irregular-plurals": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-1.4.0.tgz", - "integrity": "sha1-LKmwM2UREYVUEvFr5dd8YqRYp2Y=", - "dev": true + "integrity": "sha1-LKmwM2UREYVUEvFr5dd8YqRYp2Y=" }, "is-absolute": { "version": "1.0.0", @@ -10504,23 +11309,48 @@ "integrity": "sha1-8mWrian0RQNO9q/xWo8AsA9VF5k=", "dev": true }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" + }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", + "dev": true + }, + "is-observable": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-0.2.0.tgz", + "integrity": "sha1-s2ExHYPG5dcmyr9eJQsCNxBvWuI=", + "dev": true, + "requires": { + "symbol-observable": "0.2.4" + }, + "dependencies": { + "symbol-observable": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-0.2.4.tgz", + "integrity": "sha1-lag9smGG1q9+ehjb2XYKL4bQj0A=", + "dev": true + } + } + }, "is-odd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-1.0.0.tgz", - "integrity": "sha1-O4qTLrAos3dcObsJ6RdnrM22kIg=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz", + "integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==", "dev": true, "requires": { - "is-number": "3.0.0" + "is-number": "4.0.0" }, "dependencies": { "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "3.2.2" - } + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true } } }, @@ -10596,8 +11426,7 @@ "is-regexp": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", - "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", - "dev": true + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=" }, "is-relative": { "version": "1.0.0", @@ -10612,6 +11441,21 @@ "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.1.tgz", "integrity": "sha512-y5CXYbzvB3jTnWAZH1Nl7ykUWb6T3BcTs56HUruwBf8MhF56n1HWqhDWnVFo8GHrUPDgvUUNVhrc2U8W7iqz5g==" }, + "is-retry-allowed": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", + "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=", + "dev": true + }, + "is-scoped": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-scoped/-/is-scoped-1.0.0.tgz", + "integrity": "sha1-RJypgpnnEwOCViieyytUDcQ3yzA=", + "dev": true, + "requires": { + "scoped-regex": "1.0.0" + } + }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", @@ -10735,6 +11579,16 @@ "textextensions": "1.0.2" } }, + "isurl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", + "dev": true, + "requires": { + "has-to-string-tag-x": "1.4.1", + "is-object": "1.0.1" + } + }, "jazzicon": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/jazzicon/-/jazzicon-1.5.0.tgz", @@ -10792,6 +11646,106 @@ "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "optional": true }, + "jscodeshift": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.5.0.tgz", + "integrity": "sha512-JAcQINNMFpdzzpKJN8k5xXjF3XDuckB1/48uScSzcnNyK199iWEc9AxKL9OoX5144M2w5zEx9Qs4/E/eBZZUlw==", + "dev": true, + "requires": { + "babel-plugin-transform-flow-strip-types": "6.22.0", + "babel-preset-es2015": "6.24.1", + "babel-preset-stage-1": "6.24.1", + "babel-register": "6.26.0", + "babylon": "7.0.0-beta.43", + "colors": "1.2.1", + "flow-parser": "0.69.0", + "lodash": "4.17.4", + "micromatch": "2.3.11", + "neo-async": "2.5.0", + "node-dir": "0.1.8", + "nomnom": "1.8.1", + "recast": "0.14.7", + "temp": "0.8.3", + "write-file-atomic": "1.3.4" + }, + "dependencies": { + "ansi-styles": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", + "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=", + "dev": true + }, + "ast-types": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.11.3.tgz", + "integrity": "sha512-XA5o5dsNw8MhyW0Q7MWXJWc4oOzZKbdsEJq45h7c8q/d9DwWZ5F2ugUc1PuMLPGsUnphCt/cNDHu8JeBbxf1qA==", + "dev": true + }, + "babylon": { + "version": "7.0.0-beta.43", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.43.tgz", + "integrity": "sha512-kvgnRG/fXBtvezILk/oxGGMHKUznYqRDrnNfj/aJ1r3b1Mqx4PO3vaUrkkJIfqxLM+uwzKGcmornX3NT4pu5xw==", + "dev": true + }, + "chalk": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", + "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", + "dev": true, + "requires": { + "ansi-styles": "1.0.0", + "has-color": "0.1.7", + "strip-ansi": "0.1.1" + } + }, + "colors": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.2.1.tgz", + "integrity": "sha512-s8+wktIuDSLffCywiwSxQOMqtPxML11a/dtHE17tMn4B1MSWw/C22EKf7M2KGUBcDaVFEGT+S8N02geDXeuNKg==", + "dev": true + }, + "nomnom": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", + "integrity": "sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=", + "dev": true, + "requires": { + "chalk": "0.4.0", + "underscore": "1.6.0" + } + }, + "recast": { + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.14.7.tgz", + "integrity": "sha512-/nwm9pkrcWagN40JeJhkPaRxiHXBRkXyRh/hgU088Z/v+qCy+zIHHY6bC6o7NaKAxPqtE6nD8zBH1LfU0/Wx6A==", + "dev": true, + "requires": { + "ast-types": "0.11.3", + "esprima": "4.0.0", + "private": "0.1.8", + "source-map": "0.6.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "strip-ansi": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", + "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=", + "dev": true + }, + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", + "dev": true + } + } + }, "jsdom": { "version": "11.5.1", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.5.1.tgz", @@ -10869,6 +11823,88 @@ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" }, + "jshint": { + "version": "2.9.5", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.5.tgz", + "integrity": "sha1-HnJSkVzmgbQIJ+4UJIxG006apiw=", + "dev": true, + "requires": { + "cli": "1.0.1", + "console-browserify": "1.1.0", + "exit": "0.1.2", + "htmlparser2": "3.8.3", + "lodash": "3.7.0", + "minimatch": "3.0.4", + "shelljs": "0.3.0", + "strip-json-comments": "1.0.4" + }, + "dependencies": { + "domhandler": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", + "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", + "dev": true, + "requires": { + "domelementtype": "1.3.0" + } + }, + "entities": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", + "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", + "dev": true + }, + "htmlparser2": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", + "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", + "dev": true, + "requires": { + "domelementtype": "1.3.0", + "domhandler": "2.3.0", + "domutils": "1.5.1", + "entities": "1.0.0", + "readable-stream": "1.1.14" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "lodash": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.7.0.tgz", + "integrity": "sha1-Nni9irmVBXwHreg27S7wh9qBHUU=", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "strip-json-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", + "dev": true + } + } + }, "jshint-stylish": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/jshint-stylish/-/jshint-stylish-2.2.1.tgz", @@ -10883,11 +11919,23 @@ "text-table": "0.2.0" } }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, "json-loader": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz", "integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==" }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, "json-rpc-engine": { "version": "3.6.1", "resolved": "https://registry.npmjs.org/json-rpc-engine/-/json-rpc-engine-3.6.1.tgz", @@ -11159,6 +12207,53 @@ "array-includes": "3.0.3" } }, + "jszip": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.1.5.tgz", + "integrity": "sha512-5W8NUaFRFRqTOL7ZDDrx5qWHJyBXy6velVudIzQUSoqAAYqzSh2Z7/m0Rf1QbmQJccegD0r+YZxBjzqoBiEeJQ==", + "dev": true, + "requires": { + "core-js": "2.3.0", + "es6-promise": "3.0.2", + "lie": "3.1.1", + "pako": "1.0.6", + "readable-stream": "2.0.6" + }, + "dependencies": { + "core-js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.3.0.tgz", + "integrity": "sha1-+rg/uwstjchfpjbEudNMdUIMbWU=", + "dev": true + }, + "es6-promise": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.0.2.tgz", + "integrity": "sha1-AQ1YWEI6XxGJeWZfRkhqlcbuK7Y=", + "dev": true + }, + "readable-stream": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, "just-debounce": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.0.0.tgz", @@ -11454,6 +12549,21 @@ "sha3": "1.2.0" } }, + "kew": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", + "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=", + "dev": true + }, + "keyv": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", + "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -11765,6 +12875,23 @@ "integrity": "sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g=", "dev": true }, + "lie": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", + "integrity": "sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=", + "dev": true, + "requires": { + "immediate": "3.0.6" + }, + "dependencies": { + "immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", + "dev": true + } + } + }, "liftoff": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz", @@ -11780,6 +12907,132 @@ "resolve": "1.4.0" } }, + "listr": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/listr/-/listr-0.13.0.tgz", + "integrity": "sha1-ILsLowuuZg7oTMBQPfS+PVYjiH0=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "cli-truncate": "0.2.1", + "figures": "1.7.0", + "indent-string": "2.1.0", + "is-observable": "0.2.0", + "is-promise": "2.1.0", + "is-stream": "1.1.0", + "listr-silent-renderer": "1.1.1", + "listr-update-renderer": "0.4.0", + "listr-verbose-renderer": "0.4.1", + "log-symbols": "1.0.2", + "log-update": "1.0.2", + "ora": "0.2.3", + "p-map": "1.2.0", + "rxjs": "5.5.8", + "stream-to-observable": "0.2.0", + "strip-ansi": "3.0.1" + }, + "dependencies": { + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5", + "object-assign": "4.1.1" + } + } + } + }, + "listr-silent-renderer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", + "integrity": "sha1-kktaN1cVN3C/Go4/v3S4u/P5JC4=", + "dev": true + }, + "listr-update-renderer": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.4.0.tgz", + "integrity": "sha1-NE2YDaLKLosUW6MFkI8yrj9MyKc=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "cli-truncate": "0.2.1", + "elegant-spinner": "1.0.1", + "figures": "1.7.0", + "indent-string": "3.2.0", + "log-symbols": "1.0.2", + "log-update": "1.0.2", + "strip-ansi": "3.0.1" + }, + "dependencies": { + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5", + "object-assign": "4.1.1" + } + }, + "indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "dev": true + } + } + }, + "listr-verbose-renderer": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.4.1.tgz", + "integrity": "sha1-ggb0z21S3cWCfl/RSYng6WWTOjU=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "cli-cursor": "1.0.2", + "date-fns": "1.29.0", + "figures": "1.7.0" + }, + "dependencies": { + "cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "dev": true, + "requires": { + "restore-cursor": "1.0.1" + } + }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5", + "object-assign": "4.1.1" + } + }, + "onetime": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "dev": true + }, + "restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "dev": true, + "requires": { + "exit-hook": "1.1.1", + "onetime": "1.1.0" + } + } + } + }, "livereload-js": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.2.2.tgz", @@ -11796,6 +13049,13 @@ "pify": "2.3.0", "pinkie-promise": "2.0.1", "strip-bom": "2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } } }, "loader-runner": { @@ -11814,6 +13074,24 @@ "object-assign": "4.1.1" } }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, "lodash": { "version": "4.17.4", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", @@ -12065,6 +13343,49 @@ "chalk": "1.1.3" } }, + "log-update": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-1.0.2.tgz", + "integrity": "sha1-GZKfZMQJPS0ucHWh2tivWcKWuNE=", + "dev": true, + "requires": { + "ansi-escapes": "1.4.0", + "cli-cursor": "1.0.2" + }, + "dependencies": { + "ansi-escapes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", + "dev": true + }, + "cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "dev": true, + "requires": { + "restore-cursor": "1.0.1" + } + }, + "onetime": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "dev": true + }, + "restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "dev": true, + "requires": { + "exit-hook": "1.1.1", + "onetime": "1.1.0" + } + } + } + }, "log4js": { "version": "2.5.3", "resolved": "https://registry.npmjs.org/log4js/-/log4js-2.5.3.tgz", @@ -12305,9 +13626,9 @@ "integrity": "sha1-rgyqVhERSYxboTcj1vtjHSQAOTQ=" }, "lolex": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.3.1.tgz", - "integrity": "sha512-mQuW55GhduF3ppo+ZRUTz1PRjEh1hS5BbqU7d8D0ez2OKxHDod7StPPeAVKisZR5aLkHZjdGWSL42LSONUJsZw==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/lolex/-/lolex-2.3.2.tgz", + "integrity": "sha512-A5pN2tkFj7H0dGIAM6MFvHKMJcPnjZsOMvR7ujCjfgW5TbV6H9vb1PgxLtHvjqNZTHsUolz+6/WEO0N1xNx2ng==", "dev": true }, "longest": { @@ -12332,6 +13653,12 @@ "signal-exit": "3.0.2" } }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, "lru-cache": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", @@ -12432,6 +13759,15 @@ } } }, + "make-dir": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.2.0.tgz", + "integrity": "sha512-aNUAa4UMg/UougV25bbrU4ZaaKNjJ/3/xnvg/twpmKROPdKZPZ9wGgI0opdZzO8q/zUFawoUuixuOv33eZ61Iw==", + "dev": true, + "requires": { + "pify": "3.0.0" + } + }, "make-error": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.4.tgz", @@ -12836,6 +14172,108 @@ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, + "mem": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "dev": true, + "requires": { + "mimic-fn": "1.1.0" + } + }, + "mem-fs": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/mem-fs/-/mem-fs-1.1.3.tgz", + "integrity": "sha1-uK6NLj/Lb10/kWXBLUVRoGXZicw=", + "dev": true, + "requires": { + "through2": "2.0.3", + "vinyl": "1.2.0", + "vinyl-file": "2.0.0" + }, + "dependencies": { + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + }, + "clone-stats": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", + "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", + "dev": true + }, + "replace-ext": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", + "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", + "dev": true + }, + "vinyl": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz", + "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", + "dev": true, + "requires": { + "clone": "1.0.4", + "clone-stats": "0.0.1", + "replace-ext": "0.0.1" + } + } + } + }, + "mem-fs-editor": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mem-fs-editor/-/mem-fs-editor-3.0.2.tgz", + "integrity": "sha1-3Qpuryu4prN3QAZ6pUnrUwEFr58=", + "dev": true, + "requires": { + "commondir": "1.0.1", + "deep-extend": "0.4.2", + "ejs": "2.5.8", + "glob": "7.1.2", + "globby": "6.1.0", + "mkdirp": "0.5.1", + "multimatch": "2.1.0", + "rimraf": "2.6.2", + "through2": "2.0.3", + "vinyl": "2.1.0" + }, + "dependencies": { + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "deep-extend": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", + "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=", + "dev": true + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, "memdown": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/memdown/-/memdown-1.4.1.tgz", @@ -12911,15 +14349,6 @@ "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, - "merge-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz", - "integrity": "sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE=", - "dev": true, - "requires": { - "readable-stream": "2.3.3" - } - }, "merkle-patricia-tree": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/merkle-patricia-tree/-/merkle-patricia-tree-2.3.0.tgz", @@ -13059,6 +14488,12 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=" }, + "mimic-response": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.0.tgz", + "integrity": "sha1-3z02Uqc/3ta5sLJBRub9BSNTRY4=", + "dev": true + }, "min-document": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", @@ -13413,18 +14848,19 @@ "integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo=" }, "nanomatch": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.7.tgz", - "integrity": "sha512-/5ldsnyurvEw7wNpxLFgjVvBLMta43niEYOy0CJ4ntcYSbx6bugRUTQeFb4BR/WanEL1o3aQgHuVLHQaB6tOqg==", + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz", + "integrity": "sha512-n8R9bS8yQ6eSXaV6jHUpKzD8gLsin02w1HSFiegwrs9E098Ylhw5jdyKPaYqvHknHaSCKTPp7C8dGCQ0q9koXA==", "dev": true, "requires": { "arr-diff": "4.0.0", "array-unique": "0.3.2", - "define-property": "1.0.0", - "extend-shallow": "2.0.1", + "define-property": "2.0.2", + "extend-shallow": "3.0.2", "fragment-cache": "0.2.1", - "is-odd": "1.0.0", - "kind-of": "5.1.0", + "is-odd": "2.0.0", + "is-windows": "1.0.2", + "kind-of": "6.0.2", "object.pick": "1.3.0", "regex-not": "1.0.0", "snapdragon": "0.8.1", @@ -13443,10 +14879,45 @@ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", "dev": true }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "1.0.2", + "isobject": "3.0.1" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "1.0.0", + "is-extendable": "1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "2.0.4" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true } } @@ -13478,6 +14949,12 @@ "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" }, + "neo-async": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.5.0.tgz", + "integrity": "sha512-nJmSswG4As/MkRq7QZFuH/sf/yuv8ODdMZrY4Bedjp77a5MK4A6s7YbBB64c9u79EBUOfXUXBvArmvzTD0X+6g==", + "dev": true + }, "netmask": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz", @@ -13491,15 +14968,21 @@ "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", "dev": true }, + "nice-try": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz", + "integrity": "sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA==", + "dev": true + }, "nise": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/nise/-/nise-1.2.0.tgz", - "integrity": "sha512-q9jXh3UNsMV28KeqI43ILz5+c3l+RiNW8mhurEwCKckuHQbL+hTJIKKTiUlCPKlgQ/OukFvSnKB/Jk3+sFbkGA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/nise/-/nise-1.3.2.tgz", + "integrity": "sha512-KPKb+wvETBiwb4eTwtR/OsA2+iijXP+VnlSFYJo3EHjm2yjek1NWxHOUQat3i7xNLm1Bm18UA5j5Wor0yO2GtA==", "dev": true, "requires": { - "formatio": "1.2.0", + "@sinonjs/formatio": "2.0.0", "just-extend": "1.1.27", - "lolex": "1.6.0", + "lolex": "2.3.2", "path-to-regexp": "1.7.0", "text-encoding": "0.6.4" }, @@ -13510,12 +14993,6 @@ "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", "dev": true }, - "lolex": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.6.0.tgz", - "integrity": "sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY=", - "dev": true - }, "path-to-regexp": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", @@ -13580,6 +15057,12 @@ } } }, + "node-dir": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.8.tgz", + "integrity": "sha1-VfuN62mQcHB/tn+RpGDwRIKUx30=", + "dev": true + }, "node-fetch": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", @@ -14000,6 +15483,17 @@ "integrity": "sha1-0LFF62kRicY6eNIB3E/bEpPvDAM=", "dev": true }, + "normalize-url": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", + "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", + "dev": true, + "requires": { + "prepend-http": "2.0.0", + "query-string": "5.1.1", + "sort-keys": "2.0.0" + } + }, "now-and-later": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.0.tgz", @@ -14112,7 +15606,8 @@ "dependencies": { "align-text": { "version": "0.1.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", "dev": true, "requires": { "kind-of": "3.2.2", @@ -14122,22 +15617,26 @@ }, "amdefine": { "version": "1.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", "dev": true }, "ansi-regex": { "version": "2.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", "dev": true }, "ansi-styles": { "version": "2.2.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, "append-transform": { "version": "0.4.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz", + "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=", "dev": true, "requires": { "default-require-extensions": "1.0.0" @@ -14145,12 +15644,14 @@ }, "archy": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", "dev": true }, "arr-diff": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", "dev": true, "requires": { "arr-flatten": "1.1.0" @@ -14158,27 +15659,32 @@ }, "arr-flatten": { "version": "1.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", "dev": true }, "array-unique": { "version": "0.2.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", "dev": true }, "arrify": { "version": "1.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, "async": { "version": "1.5.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", "dev": true }, "babel-code-frame": { "version": "6.26.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", "dev": true, "requires": { "chalk": "1.1.3", @@ -14188,7 +15694,8 @@ }, "babel-generator": { "version": "6.26.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.0.tgz", + "integrity": "sha1-rBriAHC3n248odMmlhMFN3TyDcU=", "dev": true, "requires": { "babel-messages": "6.23.0", @@ -14203,7 +15710,8 @@ }, "babel-messages": { "version": "6.23.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", "dev": true, "requires": { "babel-runtime": "6.26.0" @@ -14211,7 +15719,8 @@ }, "babel-runtime": { "version": "6.26.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "dev": true, "requires": { "core-js": "2.5.3", @@ -14220,7 +15729,8 @@ }, "babel-template": { "version": "6.26.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", "dev": true, "requires": { "babel-runtime": "6.26.0", @@ -14232,7 +15742,8 @@ }, "babel-traverse": { "version": "6.26.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", "dev": true, "requires": { "babel-code-frame": "6.26.0", @@ -14248,7 +15759,8 @@ }, "babel-types": { "version": "6.26.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", "dev": true, "requires": { "babel-runtime": "6.26.0", @@ -14259,17 +15771,20 @@ }, "babylon": { "version": "6.18.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", "dev": true }, "balanced-match": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, "brace-expansion": { "version": "1.1.8", - "bundled": true, + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", "dev": true, "requires": { "balanced-match": "1.0.0", @@ -14278,7 +15793,8 @@ }, "braces": { "version": "1.8.5", - "bundled": true, + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", "dev": true, "requires": { "expand-range": "1.8.2", @@ -14288,12 +15804,14 @@ }, "builtin-modules": { "version": "1.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", "dev": true }, "caching-transform": { "version": "1.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-1.0.1.tgz", + "integrity": "sha1-bb2y8g+Nj7znnz6U6dF0Lc31wKE=", "dev": true, "requires": { "md5-hex": "1.3.0", @@ -14303,13 +15821,15 @@ }, "camelcase": { "version": "1.2.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", "dev": true, "optional": true }, "center-align": { "version": "0.1.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", "dev": true, "optional": true, "requires": { @@ -14319,7 +15839,8 @@ }, "chalk": { "version": "1.1.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { "ansi-styles": "2.2.1", @@ -14331,7 +15852,8 @@ }, "cliui": { "version": "2.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", "dev": true, "optional": true, "requires": { @@ -14342,7 +15864,8 @@ "dependencies": { "wordwrap": { "version": "0.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", "dev": true, "optional": true } @@ -14350,32 +15873,38 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, "commondir": { "version": "1.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", "dev": true }, "concat-map": { "version": "0.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, "convert-source-map": { "version": "1.5.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", + "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", "dev": true }, "core-js": { "version": "2.5.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz", + "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=", "dev": true }, "cross-spawn": { "version": "4.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz", + "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=", "dev": true, "requires": { "lru-cache": "4.1.1", @@ -14384,7 +15913,8 @@ }, "debug": { "version": "2.6.9", - "bundled": true, + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { "ms": "2.0.0" @@ -14392,17 +15922,20 @@ }, "debug-log": { "version": "1.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/debug-log/-/debug-log-1.0.1.tgz", + "integrity": "sha1-IwdjLUwEOCuN+KMvcLiVBG1SdF8=", "dev": true }, "decamelize": { "version": "1.2.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, "default-require-extensions": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", + "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=", "dev": true, "requires": { "strip-bom": "2.0.0" @@ -14410,7 +15943,8 @@ }, "detect-indent": { "version": "4.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", "dev": true, "requires": { "repeating": "2.0.1" @@ -14418,7 +15952,8 @@ }, "error-ex": { "version": "1.3.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", "dev": true, "requires": { "is-arrayish": "0.2.1" @@ -14426,17 +15961,20 @@ }, "escape-string-regexp": { "version": "1.0.5", - "bundled": true, + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", "dev": true }, "esutils": { "version": "2.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, "execa": { "version": "0.7.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "dev": true, "requires": { "cross-spawn": "5.1.0", @@ -14450,7 +15988,8 @@ "dependencies": { "cross-spawn": { "version": "5.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "dev": true, "requires": { "lru-cache": "4.1.1", @@ -14462,7 +16001,8 @@ }, "expand-brackets": { "version": "0.1.5", - "bundled": true, + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", "dev": true, "requires": { "is-posix-bracket": "0.1.1" @@ -14470,7 +16010,8 @@ }, "expand-range": { "version": "1.8.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", "dev": true, "requires": { "fill-range": "2.2.3" @@ -14478,7 +16019,8 @@ }, "extglob": { "version": "0.3.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", "dev": true, "requires": { "is-extglob": "1.0.0" @@ -14486,12 +16028,14 @@ }, "filename-regex": { "version": "2.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", "dev": true }, "fill-range": { "version": "2.2.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", + "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", "dev": true, "requires": { "is-number": "2.1.0", @@ -14503,7 +16047,8 @@ }, "find-cache-dir": { "version": "0.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz", + "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=", "dev": true, "requires": { "commondir": "1.0.1", @@ -14513,7 +16058,8 @@ }, "find-up": { "version": "2.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { "locate-path": "2.0.0" @@ -14521,12 +16067,14 @@ }, "for-in": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", "dev": true }, "for-own": { "version": "0.1.5", - "bundled": true, + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", "dev": true, "requires": { "for-in": "1.0.2" @@ -14534,7 +16082,8 @@ }, "foreground-child": { "version": "1.5.6", - "bundled": true, + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-1.5.6.tgz", + "integrity": "sha1-T9ca0t/elnibmApcCilZN8svXOk=", "dev": true, "requires": { "cross-spawn": "4.0.2", @@ -14543,22 +16092,26 @@ }, "fs.realpath": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, "get-caller-file": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", + "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", "dev": true }, "get-stream": { "version": "3.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", "dev": true }, "glob": { "version": "7.1.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { "fs.realpath": "1.0.0", @@ -14571,7 +16124,8 @@ }, "glob-base": { "version": "0.3.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", "dev": true, "requires": { "glob-parent": "2.0.0", @@ -14580,7 +16134,8 @@ }, "glob-parent": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", "dev": true, "requires": { "is-glob": "2.0.1" @@ -14588,17 +16143,20 @@ }, "globals": { "version": "9.18.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", "dev": true }, "graceful-fs": { "version": "4.1.11", - "bundled": true, + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", "dev": true }, "handlebars": { "version": "4.0.11", - "bundled": true, + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", + "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", "dev": true, "requires": { "async": "1.5.2", @@ -14609,7 +16167,8 @@ "dependencies": { "source-map": { "version": "0.4.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", "dev": true, "requires": { "amdefine": "1.0.1" @@ -14619,7 +16178,8 @@ }, "has-ansi": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", "dev": true, "requires": { "ansi-regex": "2.1.1" @@ -14627,22 +16187,26 @@ }, "has-flag": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", "dev": true }, "hosted-git-info": { "version": "2.5.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", + "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", "dev": true }, "imurmurhash": { "version": "0.1.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, "inflight": { "version": "1.0.6", - "bundled": true, + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { "once": "1.4.0", @@ -14651,12 +16215,14 @@ }, "inherits": { "version": "2.0.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", "dev": true }, "invariant": { "version": "2.2.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", + "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", "dev": true, "requires": { "loose-envify": "1.3.1" @@ -14664,22 +16230,26 @@ }, "invert-kv": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", "dev": true }, "is-arrayish": { "version": "0.2.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, "is-buffer": { "version": "1.1.6", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", "dev": true }, "is-builtin-module": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { "builtin-modules": "1.1.1" @@ -14687,12 +16257,14 @@ }, "is-dotfile": { "version": "1.0.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", "dev": true }, "is-equal-shallow": { "version": "0.1.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", "dev": true, "requires": { "is-primitive": "2.0.0" @@ -14700,17 +16272,20 @@ }, "is-extendable": { "version": "0.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", "dev": true }, "is-extglob": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", "dev": true }, "is-finite": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", "dev": true, "requires": { "number-is-nan": "1.0.1" @@ -14718,7 +16293,8 @@ }, "is-fullwidth-code-point": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, "requires": { "number-is-nan": "1.0.1" @@ -14726,7 +16302,8 @@ }, "is-glob": { "version": "2.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", "dev": true, "requires": { "is-extglob": "1.0.0" @@ -14734,7 +16311,8 @@ }, "is-number": { "version": "2.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", "dev": true, "requires": { "kind-of": "3.2.2" @@ -14742,37 +16320,44 @@ }, "is-posix-bracket": { "version": "0.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", "dev": true }, "is-primitive": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", "dev": true }, "is-stream": { "version": "1.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "dev": true }, "is-utf8": { "version": "0.2.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", "dev": true }, "isarray": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, "isexe": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, "isobject": { "version": "2.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", "dev": true, "requires": { "isarray": "1.0.0" @@ -14780,12 +16365,14 @@ }, "istanbul-lib-coverage": { "version": "1.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.1.tgz", + "integrity": "sha512-0+1vDkmzxqJIn5rcoEqapSB4DmPxE31EtI2dF2aCkV5esN9EWHxZ0dwgDClivMXJqE7zaYQxq30hj5L0nlTN5Q==", "dev": true }, "istanbul-lib-hook": { "version": "1.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.1.0.tgz", + "integrity": "sha512-U3qEgwVDUerZ0bt8cfl3dSP3S6opBoOtk3ROO5f2EfBr/SRiD9FQqzwaZBqFORu8W7O0EXpai+k7kxHK13beRg==", "dev": true, "requires": { "append-transform": "0.4.0" @@ -14793,7 +16380,8 @@ }, "istanbul-lib-instrument": { "version": "1.9.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.9.1.tgz", + "integrity": "sha512-RQmXeQ7sphar7k7O1wTNzVczF9igKpaeGQAG9qR2L+BS4DCJNTI9nytRmIVYevwO0bbq+2CXvJmYDuz0gMrywA==", "dev": true, "requires": { "babel-generator": "6.26.0", @@ -14807,7 +16395,8 @@ }, "istanbul-lib-report": { "version": "1.1.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.2.tgz", + "integrity": "sha512-UTv4VGx+HZivJQwAo1wnRwe1KTvFpfi/NYwN7DcsrdzMXwpRT/Yb6r4SBPoHWj4VuQPakR32g4PUUeyKkdDkBA==", "dev": true, "requires": { "istanbul-lib-coverage": "1.1.1", @@ -14818,7 +16407,8 @@ "dependencies": { "supports-color": { "version": "3.2.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", "dev": true, "requires": { "has-flag": "1.0.0" @@ -14828,7 +16418,8 @@ }, "istanbul-lib-source-maps": { "version": "1.2.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.2.tgz", + "integrity": "sha512-8BfdqSfEdtip7/wo1RnrvLpHVEd8zMZEDmOFEnpC6dg0vXflHt9nvoAyQUzig2uMSXfF2OBEYBV3CVjIL9JvaQ==", "dev": true, "requires": { "debug": "3.1.0", @@ -14840,7 +16431,8 @@ "dependencies": { "debug": { "version": "3.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "dev": true, "requires": { "ms": "2.0.0" @@ -14850,7 +16442,8 @@ }, "istanbul-reports": { "version": "1.1.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.1.3.tgz", + "integrity": "sha512-ZEelkHh8hrZNI5xDaKwPMFwDsUf5wIEI2bXAFGp1e6deR2mnEKBPhLJEgr4ZBt8Gi6Mj38E/C8kcy9XLggVO2Q==", "dev": true, "requires": { "handlebars": "4.0.11" @@ -14858,17 +16451,20 @@ }, "js-tokens": { "version": "3.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", "dev": true }, "jsesc": { "version": "1.3.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", "dev": true }, "kind-of": { "version": "3.2.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { "is-buffer": "1.1.6" @@ -14876,13 +16472,15 @@ }, "lazy-cache": { "version": "1.0.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", "dev": true, "optional": true }, "lcid": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "dev": true, "requires": { "invert-kv": "1.0.0" @@ -14890,7 +16488,8 @@ }, "load-json-file": { "version": "1.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { "graceful-fs": "4.1.11", @@ -14902,7 +16501,8 @@ }, "locate-path": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { "p-locate": "2.0.0", @@ -14911,24 +16511,28 @@ "dependencies": { "path-exists": { "version": "3.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true } } }, "lodash": { "version": "4.17.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", "dev": true }, "longest": { "version": "1.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", "dev": true }, "loose-envify": { "version": "1.3.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", + "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", "dev": true, "requires": { "js-tokens": "3.0.2" @@ -14936,7 +16540,8 @@ }, "lru-cache": { "version": "4.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", + "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", "dev": true, "requires": { "pseudomap": "1.0.2", @@ -14945,7 +16550,8 @@ }, "md5-hex": { "version": "1.3.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-1.3.0.tgz", + "integrity": "sha1-0sSv6YPENwZiF5uMrRRSGRNQRsQ=", "dev": true, "requires": { "md5-o-matic": "0.1.1" @@ -14953,12 +16559,14 @@ }, "md5-o-matic": { "version": "0.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/md5-o-matic/-/md5-o-matic-0.1.1.tgz", + "integrity": "sha1-givM1l4RfFFPqxdrJZRdVBAKA8M=", "dev": true }, "mem": { "version": "1.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", "dev": true, "requires": { "mimic-fn": "1.1.0" @@ -14966,7 +16574,8 @@ }, "merge-source-map": { "version": "1.0.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.0.4.tgz", + "integrity": "sha1-pd5GU42uhNQRTMXqArR3KmNGcB8=", "dev": true, "requires": { "source-map": "0.5.7" @@ -14974,7 +16583,8 @@ }, "micromatch": { "version": "2.3.11", - "bundled": true, + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", "dev": true, "requires": { "arr-diff": "2.0.0", @@ -14994,12 +16604,14 @@ }, "mimic-fn": { "version": "1.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", + "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=", "dev": true }, "minimatch": { "version": "3.0.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { "brace-expansion": "1.1.8" @@ -15007,12 +16619,14 @@ }, "minimist": { "version": "0.0.8", - "bundled": true, + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, "mkdirp": { "version": "0.5.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "requires": { "minimist": "0.0.8" @@ -15020,12 +16634,14 @@ }, "ms": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, "normalize-package-data": { "version": "2.4.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", "dev": true, "requires": { "hosted-git-info": "2.5.0", @@ -15036,7 +16652,8 @@ }, "normalize-path": { "version": "2.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", "dev": true, "requires": { "remove-trailing-separator": "1.1.0" @@ -15044,7 +16661,8 @@ }, "npm-run-path": { "version": "2.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "dev": true, "requires": { "path-key": "2.0.1" @@ -15052,17 +16670,20 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, "object-assign": { "version": "4.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, "object.omit": { "version": "2.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", "dev": true, "requires": { "for-own": "0.1.5", @@ -15071,7 +16692,8 @@ }, "once": { "version": "1.4.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { "wrappy": "1.0.2" @@ -15079,7 +16701,8 @@ }, "optimist": { "version": "0.6.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", "dev": true, "requires": { "minimist": "0.0.8", @@ -15088,12 +16711,14 @@ }, "os-homedir": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", "dev": true }, "os-locale": { "version": "2.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", "dev": true, "requires": { "execa": "0.7.0", @@ -15103,17 +16728,20 @@ }, "p-finally": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, "p-limit": { "version": "1.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz", + "integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw=", "dev": true }, "p-locate": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { "p-limit": "1.1.0" @@ -15121,7 +16749,8 @@ }, "parse-glob": { "version": "3.0.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", "dev": true, "requires": { "glob-base": "0.3.0", @@ -15132,7 +16761,8 @@ }, "parse-json": { "version": "2.2.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "requires": { "error-ex": "1.3.1" @@ -15140,7 +16770,8 @@ }, "path-exists": { "version": "2.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, "requires": { "pinkie-promise": "2.0.1" @@ -15148,22 +16779,26 @@ }, "path-is-absolute": { "version": "1.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, "path-key": { "version": "2.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true }, "path-parse": { "version": "1.0.5", - "bundled": true, + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", "dev": true }, "path-type": { "version": "1.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "dev": true, "requires": { "graceful-fs": "4.1.11", @@ -15173,17 +16808,20 @@ }, "pify": { "version": "2.3.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", "dev": true }, "pinkie": { "version": "2.0.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", "dev": true }, "pinkie-promise": { "version": "2.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { "pinkie": "2.0.4" @@ -15191,7 +16829,8 @@ }, "pkg-dir": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", "dev": true, "requires": { "find-up": "1.1.2" @@ -15199,7 +16838,8 @@ "dependencies": { "find-up": { "version": "1.1.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { "path-exists": "2.1.0", @@ -15210,17 +16850,20 @@ }, "preserve": { "version": "0.2.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", "dev": true }, "pseudomap": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", "dev": true }, "randomatic": { "version": "1.1.7", - "bundled": true, + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", + "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", "dev": true, "requires": { "is-number": "3.0.0", @@ -15229,7 +16872,8 @@ "dependencies": { "is-number": { "version": "3.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", "dev": true, "requires": { "kind-of": "3.2.2" @@ -15237,7 +16881,8 @@ "dependencies": { "kind-of": { "version": "3.2.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", "dev": true, "requires": { "is-buffer": "1.1.6" @@ -15247,7 +16892,8 @@ }, "kind-of": { "version": "4.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", "dev": true, "requires": { "is-buffer": "1.1.6" @@ -15257,7 +16903,8 @@ }, "read-pkg": { "version": "1.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "dev": true, "requires": { "load-json-file": "1.1.0", @@ -15267,7 +16914,8 @@ }, "read-pkg-up": { "version": "1.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "dev": true, "requires": { "find-up": "1.1.2", @@ -15276,7 +16924,8 @@ "dependencies": { "find-up": { "version": "1.1.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { "path-exists": "2.1.0", @@ -15287,12 +16936,14 @@ }, "regenerator-runtime": { "version": "0.11.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", "dev": true }, "regex-cache": { "version": "0.4.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", "dev": true, "requires": { "is-equal-shallow": "0.1.3" @@ -15300,22 +16951,26 @@ }, "remove-trailing-separator": { "version": "1.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", "dev": true }, "repeat-element": { "version": "1.1.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", "dev": true }, "repeat-string": { "version": "1.6.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true }, "repeating": { "version": "2.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", "dev": true, "requires": { "is-finite": "1.0.2" @@ -15323,22 +16978,26 @@ }, "require-directory": { "version": "2.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, "require-main-filename": { "version": "1.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "dev": true }, "resolve-from": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=", "dev": true }, "right-align": { "version": "0.1.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", "dev": true, "optional": true, "requires": { @@ -15347,7 +17006,8 @@ }, "rimraf": { "version": "2.6.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { "glob": "7.1.2" @@ -15355,17 +17015,20 @@ }, "semver": { "version": "5.4.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", + "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", "dev": true }, "set-blocking": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, "shebang-command": { "version": "1.2.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "requires": { "shebang-regex": "1.0.0" @@ -15373,27 +17036,32 @@ }, "shebang-regex": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, "signal-exit": { "version": "3.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, "slide": { "version": "1.1.6", - "bundled": true, + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", "dev": true }, "source-map": { "version": "0.5.7", - "bundled": true, + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "dev": true }, "spawn-wrap": { "version": "1.4.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-1.4.2.tgz", + "integrity": "sha512-vMwR3OmmDhnxCVxM8M+xO/FtIp6Ju/mNaDfCMMW7FDcLRTPFWUswec4LXJHTJE2hwTI9O0YBfygu4DalFl7Ylg==", "dev": true, "requires": { "foreground-child": "1.5.6", @@ -15406,7 +17074,8 @@ }, "spdx-correct": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", "dev": true, "requires": { "spdx-license-ids": "1.2.2" @@ -15414,17 +17083,20 @@ }, "spdx-expression-parse": { "version": "1.0.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", + "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", "dev": true }, "spdx-license-ids": { "version": "1.2.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", "dev": true }, "string-width": { "version": "2.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "dev": true, "requires": { "is-fullwidth-code-point": "2.0.0", @@ -15433,17 +17105,20 @@ "dependencies": { "ansi-regex": { "version": "3.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", "dev": true }, "is-fullwidth-code-point": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, "strip-ansi": { "version": "4.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "dev": true, "requires": { "ansi-regex": "3.0.0" @@ -15453,7 +17128,8 @@ }, "strip-ansi": { "version": "3.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { "ansi-regex": "2.1.1" @@ -15461,7 +17137,8 @@ }, "strip-bom": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, "requires": { "is-utf8": "0.2.1" @@ -15469,17 +17146,20 @@ }, "strip-eof": { "version": "1.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", "dev": true }, "supports-color": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", "dev": true }, "test-exclude": { "version": "4.1.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-4.1.1.tgz", + "integrity": "sha512-35+Asrsk3XHJDBgf/VRFexPgh3UyETv8IAn/LRTiZjVy6rjPVqdEk8dJcJYBzl1w0XCJM48lvTy8SfEsCWS4nA==", "dev": true, "requires": { "arrify": "1.0.1", @@ -15491,17 +17171,20 @@ }, "to-fast-properties": { "version": "1.0.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", "dev": true }, "trim-right": { "version": "1.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", "dev": true }, "uglify-js": { "version": "2.8.29", - "bundled": true, + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", "dev": true, "optional": true, "requires": { @@ -15512,7 +17195,8 @@ "dependencies": { "yargs": { "version": "3.10.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", "dev": true, "optional": true, "requires": { @@ -15526,13 +17210,15 @@ }, "uglify-to-browserify": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", "dev": true, "optional": true }, "validate-npm-package-license": { "version": "3.0.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", "dev": true, "requires": { "spdx-correct": "1.0.2", @@ -15541,7 +17227,8 @@ }, "which": { "version": "1.3.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", + "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", "dev": true, "requires": { "isexe": "2.0.0" @@ -15549,23 +17236,27 @@ }, "which-module": { "version": "2.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, "window-size": { "version": "0.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", "dev": true, "optional": true }, "wordwrap": { "version": "0.0.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", "dev": true }, "wrap-ansi": { "version": "2.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "dev": true, "requires": { "string-width": "1.0.2", @@ -15574,7 +17265,8 @@ "dependencies": { "string-width": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { "code-point-at": "1.1.0", @@ -15586,12 +17278,14 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, "write-file-atomic": { "version": "1.3.4", - "bundled": true, + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", + "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", "dev": true, "requires": { "graceful-fs": "4.1.11", @@ -15601,17 +17295,20 @@ }, "y18n": { "version": "3.2.1", - "bundled": true, + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", "dev": true }, "yallist": { "version": "2.1.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", "dev": true }, "yargs": { "version": "10.0.3", - "bundled": true, + "resolved": "https://registry.npmjs.org/yargs/-/yargs-10.0.3.tgz", + "integrity": "sha512-DqBpQ8NAUX4GyPP/ijDGHsJya4tYqLQrjPr95HNsr1YwL3+daCfvBwg7+gIC6IdJhR2kATh3hb61vjzMWEtjdw==", "dev": true, "requires": { "cliui": "3.2.0", @@ -15630,7 +17327,8 @@ "dependencies": { "cliui": { "version": "3.2.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", "dev": true, "requires": { "string-width": "1.0.2", @@ -15640,7 +17338,8 @@ "dependencies": { "string-width": { "version": "1.0.2", - "bundled": true, + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { "code-point-at": "1.1.0", @@ -15654,7 +17353,8 @@ }, "yargs-parser": { "version": "8.0.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.0.0.tgz", + "integrity": "sha1-IdR2Mw5agieaS4gTRb8GYQLiGcY=", "dev": true, "requires": { "camelcase": "4.1.0" @@ -15662,7 +17362,8 @@ "dependencies": { "camelcase": { "version": "4.1.0", - "bundled": true, + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", "dev": true } } @@ -16020,6 +17721,45 @@ "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=", "dev": true }, + "ora": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/ora/-/ora-0.2.3.tgz", + "integrity": "sha1-N1J9Igrc1Tw5tzVx11QVbV22V6Q=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "cli-cursor": "1.0.2", + "cli-spinners": "0.1.2", + "object-assign": "4.1.1" + }, + "dependencies": { + "cli-cursor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", + "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", + "dev": true, + "requires": { + "restore-cursor": "1.0.1" + } + }, + "onetime": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "dev": true + }, + "restore-cursor": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", + "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", + "dev": true, + "requires": { + "exit-hook": "1.1.1", + "onetime": "1.1.0" + } + } + } + }, "ordered-read-streams": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", @@ -16069,18 +17809,84 @@ "shell-quote": "1.6.1" } }, + "p-cancelable": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", + "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==", + "dev": true + }, + "p-each-series": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", + "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", + "dev": true, + "requires": { + "p-reduce": "1.0.0" + } + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, + "p-is-promise": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", + "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=", + "dev": true + }, + "p-lazy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-lazy/-/p-lazy-1.0.0.tgz", + "integrity": "sha1-7FPIAvLuOsKPFmzILQsrAt4nqDU=", + "dev": true + }, + "p-limit": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", + "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", + "dev": true, + "requires": { + "p-try": "1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "1.2.0" + } + }, "p-map": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", "dev": true }, + "p-reduce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", + "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", + "dev": true + }, + "p-timeout": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", + "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", + "dev": true, + "requires": { + "p-finally": "1.0.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, "pac-proxy-agent": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-1.1.0.tgz", @@ -16340,6 +18146,13 @@ "graceful-fs": "4.1.11", "pify": "2.3.0", "pinkie-promise": "2.0.1" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } } }, "pathval": { @@ -16369,6 +18182,12 @@ "sha.js": "2.4.9" } }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, "percentile": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/percentile/-/percentile-1.2.0.tgz", @@ -16380,9 +18199,9 @@ "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" }, "ping-pong-stream": { "version": "1.0.0", @@ -16492,7 +18311,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/plur/-/plur-2.1.2.tgz", "integrity": "sha1-dIJFLBoPUI4+NE6uwxLJHCncZVo=", - "dev": true, "requires": { "irregular-plurals": "1.4.0" } @@ -16508,6 +18326,147 @@ "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", "dev": true }, + "png-file-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/png-file-stream/-/png-file-stream-1.0.0.tgz", + "integrity": "sha1-4IPQ/lbgl6XL0NNBoThzeQUsrTU=", + "dev": true, + "requires": { + "glob-stream": "3.1.18", + "png-js": "0.1.1", + "through2": "0.2.3" + }, + "dependencies": { + "glob": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", + "integrity": "sha1-xstz0yJsHv7wTePFbQEvAzd+4V8=", + "dev": true, + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "2.0.10", + "once": "1.4.0" + } + }, + "glob-stream": { + "version": "3.1.18", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-3.1.18.tgz", + "integrity": "sha1-kXCl8St5Awb9/lmPMT+PeVT9FDs=", + "dev": true, + "requires": { + "glob": "4.5.3", + "glob2base": "0.0.12", + "minimatch": "2.0.10", + "ordered-read-streams": "0.1.0", + "through2": "0.6.5", + "unique-stream": "1.0.0" + }, + "dependencies": { + "through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "dev": true, + "requires": { + "readable-stream": "1.0.34", + "xtend": "4.0.1" + } + } + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "minimatch": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", + "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", + "dev": true, + "requires": { + "brace-expansion": "1.1.8" + } + }, + "object-keys": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", + "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=", + "dev": true + }, + "ordered-read-streams": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz", + "integrity": "sha1-/VZamvjrRHO6abbtijQ1LLVS8SY=", + "dev": true + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "through2": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.2.3.tgz", + "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=", + "dev": true, + "requires": { + "readable-stream": "1.1.14", + "xtend": "2.1.2" + }, + "dependencies": { + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "xtend": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", + "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", + "dev": true, + "requires": { + "object-keys": "0.4.0" + } + } + } + }, + "unique-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-1.0.0.tgz", + "integrity": "sha1-1ZpKdUJ0R9mqbJHnAmP40mpLEEs=", + "dev": true + } + } + }, + "png-js": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/png-js/-/png-js-0.1.1.tgz", + "integrity": "sha1-HMfCEjA6yr50Jj7DrHgAlYAkLZM=", + "dev": true + }, "pojo-migrator": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/pojo-migrator/-/pojo-migrator-2.1.0.tgz", @@ -16825,11 +18784,23 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, "preserve": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=" }, + "prettier": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.11.1.tgz", + "integrity": "sha512-T/KD65Ot0PB97xTrG8afQ46x3oiVhnfGjGESSI9NWYcG92+OUPZKkwHqGWXH2t9jK1crnQjubECW0FuOth+hxw==", + "dev": true + }, "pretty-bytes": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-0.1.2.tgz", @@ -16982,6 +18953,15 @@ "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" }, + "ps-tree": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.1.0.tgz", + "integrity": "sha1-tCGyQUDWID8e08dplrRCewjowBQ=", + "dev": true, + "requires": { + "event-stream": "3.3.4" + } + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -17055,6 +19035,17 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" }, + "query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "dev": true, + "requires": { + "decode-uri-component": "0.2.0", + "object-assign": "4.1.1", + "strict-uri-encode": "1.1.0" + } + }, "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", @@ -17535,6 +19526,16 @@ "mute-stream": "0.0.7" } }, + "read-chunk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-2.1.0.tgz", + "integrity": "sha1-agTAkoAF7Z1C4aasVgDhnLx/9lU=", + "dev": true, + "requires": { + "pify": "3.0.0", + "safe-buffer": "5.1.1" + } + }, "read-file-stdin": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/read-file-stdin/-/read-file-stdin-0.2.1.tgz", @@ -18018,6 +20019,23 @@ "path-parse": "1.0.5" } }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "3.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + } + } + }, "resolve-dir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", @@ -18051,6 +20069,15 @@ "integrity": "sha1-2ksXzHaEyYyWK+tNlfZoyNytCdU=", "dev": true }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "1.0.1" + } + }, "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", @@ -18146,11 +20173,37 @@ "rx-lite": "4.0.8" } }, + "rxjs": { + "version": "5.5.8", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.8.tgz", + "integrity": "sha512-Bz7qou7VAIoGiglJZbzbXa4vpX5BmTTN2Dj/se6+SwADtw4SihqBIiEa7VmTXJ8pynvq0iFr5Gx9VLyye1rIxQ==", + "dev": true, + "requires": { + "symbol-observable": "1.0.1" + }, + "dependencies": { + "symbol-observable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz", + "integrity": "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ=", + "dev": true + } + } + }, "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "0.1.15" + } + }, "samsam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.3.0.tgz", @@ -18235,6 +20288,12 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "dev": true }, + "scoped-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/scoped-regex/-/scoped-regex-1.0.0.tgz", + "integrity": "sha1-o0a7Gs1CB65wvXwMfKnlZra63bg=", + "dev": true + }, "script-injector": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/script-injector/-/script-injector-1.0.0.tgz", @@ -18331,6 +20390,29 @@ "safe-buffer": "5.1.1" } }, + "selenium-webdriver": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", + "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", + "dev": true, + "requires": { + "jszip": "3.1.5", + "rimraf": "2.6.2", + "tmp": "0.0.30", + "xml2js": "0.4.19" + }, + "dependencies": { + "tmp": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=", + "dev": true, + "requires": { + "os-tmpdir": "1.0.2" + } + } + } + }, "semaphore": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/semaphore/-/semaphore-1.1.0.tgz", @@ -18475,6 +20557,138 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" }, + "shell-parallel": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/shell-parallel/-/shell-parallel-1.0.3.tgz", + "integrity": "sha512-h8uh4DChqYYstF2QXEyU1DaWIy0S9MaeH1HHWQfV91BV2ORJftRw3XjJtVHL9GopTpKXvTUYJ6uvcdwkxSFr9w==", + "dev": true, + "requires": { + "once": "1.4.0", + "pify": "3.0.0", + "ps-tree": "1.1.0", + "yargs": "11.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "cliui": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.0.0.tgz", + "integrity": "sha512-nY3W5Gu2racvdDk//ELReY+dHjb9PlIcVDFXP72nVIhq2Gy3LuVXYwJoPVudwQnv1shtohpgkdCKT2YaKY0CKw==", + "dev": true, + "requires": { + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "wrap-ansi": "2.1.0" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "2.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "yargs": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.0.0.tgz", + "integrity": "sha512-Rjp+lMYQOWtgqojx1dEWorjCofi1YN7AoFvYV7b1gx/7dAAeuI4kN5SZiEvr0ZmsZTOpDRcCqrpI10L31tFkBw==", + "dev": true, + "requires": { + "cliui": "4.0.0", + "decamelize": "1.2.0", + "find-up": "2.1.0", + "get-caller-file": "1.0.2", + "os-locale": "2.1.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "9.0.2" + } + }, + "yargs-parser": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", + "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", + "dev": true, + "requires": { + "camelcase": "4.1.0" + } + } + } + }, "shell-quote": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", @@ -18487,6 +20701,12 @@ "jsonify": "0.0.0" } }, + "shelljs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", + "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", + "dev": true + }, "shellwords": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", @@ -18505,16 +20725,16 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, "sinon": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-4.1.3.tgz", - "integrity": "sha512-c7u0ZuvBRX1eXuB4jN3BRCAOGiUTlM8SE3TxbJHrNiHUKL7wonujMOB6Fi1gQc00U91IscFORQHDga/eccqpbw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-5.0.0.tgz", + "integrity": "sha512-dMX7ZB2E1iQ5DOEOePoNJQp03uyhdMfb+kLXlNPbquv2FwfezD+0GbbHSgCw4MFhpSSS9NMoYJfOPMjCMJtXWA==", "dev": true, "requires": { "diff": "3.3.1", "formatio": "1.2.0", "lodash.get": "4.4.2", - "lolex": "2.3.1", - "nise": "1.2.0", + "lolex": "2.3.2", + "nise": "1.3.2", "supports-color": "4.5.0", "type-detect": "4.0.5" }, @@ -18566,6 +20786,12 @@ } } }, + "slide": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", + "dev": true + }, "smart-buffer": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-1.1.15.tgz", @@ -18896,9 +21122,9 @@ } }, "solc": { - "version": "0.4.20", - "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.20.tgz", - "integrity": "sha512-LrP3Jp4FS3y8sduIR67y8Ss1riR3fggk5sMnx4OSCcU88Ro0e51+KVXyfH3NP6ghLo7COrLx/lGUaDDugCzdgA==", + "version": "0.4.21", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.4.21.tgz", + "integrity": "sha512-8lJmimVjOG9AJOQRWS2ph4rSctPMsPGZ4H360HLs5iI+euUlt7iAvUxSLeFZZzwk0kas4Qta7HmlMXNU3yYwhw==", "requires": { "fs-extra": "0.30.0", "memorystream": "0.3.1", @@ -18939,6 +21165,15 @@ } } }, + "sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", + "dev": true, + "requires": { + "is-plain-obj": "1.1.0" + } + }, "source-list-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", @@ -19461,6 +21696,15 @@ } } }, + "stream-to-observable": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/stream-to-observable/-/stream-to-observable-0.2.0.tgz", + "integrity": "sha1-WdbqOT2HwsDdrBCqDVYbxrpvDhA=", + "dev": true, + "requires": { + "any-observable": "0.2.0" + } + }, "streamroller": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz", @@ -19484,6 +21728,12 @@ } } }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true + }, "string-length": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz", @@ -19493,6 +21743,12 @@ "strip-ansi": "3.0.1" } }, + "string-template": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", + "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=", + "dev": true + }, "string-width": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", @@ -19521,6 +21777,16 @@ "safe-buffer": "5.1.1" } }, + "stringify-object": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-3.2.2.tgz", + "integrity": "sha512-O696NF21oLiDy8PhpWu8AEqoZHw++QW6mUv0UvKZe8gWSdSvMXkiLufK7OmnP27Dro4GU5kb9U7JIO0mBuCRQg==", + "requires": { + "get-own-enumerable-property-symbols": "2.0.1", + "is-obj": "1.0.1", + "is-regexp": "1.0.0" + } + }, "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", @@ -19636,6 +21902,14 @@ "object-assign": "4.1.1", "pify": "2.3.0", "pinkie-promise": "2.0.1" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } } }, "has-flag": { @@ -19900,6 +22174,12 @@ "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", @@ -20113,6 +22393,27 @@ "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=", "dev": true }, + "sw-controller": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sw-controller/-/sw-controller-1.0.3.tgz", + "integrity": "sha512-q+rS4v7kj1MPDxFRyl8GAICw/BbQzewd5HhVDNIPLnyvKtcpxi26fVXReUeUMRl4CRL/fX56PvKKqxtKhAaMpg==", + "requires": { + "babel-preset-es2015": "6.24.1", + "babel-runtime": "6.26.0", + "babelify": "7.3.0" + }, + "dependencies": { + "babelify": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz", + "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=", + "requires": { + "babel-core": "6.26.0", + "object-assign": "4.1.1" + } + } + } + }, "sw-stream": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/sw-stream/-/sw-stream-2.0.2.tgz", @@ -20298,16 +22599,22 @@ "inherits": "2.0.3" } }, - "ternary-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ternary-stream/-/ternary-stream-2.0.1.tgz", - "integrity": "sha1-Bk5Im0tb9gumpre8fy9cJ07Pgmk=", + "temp": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz", + "integrity": "sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k=", "dev": true, "requires": { - "duplexify": "3.5.1", - "fork-stream": "0.0.4", - "merge-stream": "1.0.1", - "through2": "2.0.3" + "os-tmpdir": "1.0.2", + "rimraf": "2.2.8" + }, + "dependencies": { + "rimraf": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", + "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", + "dev": true + } } }, "testem": { @@ -20577,11 +22884,25 @@ "dev": true, "optional": true }, + "tildify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz", + "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", + "requires": { + "os-homedir": "1.0.2" + } + }, "time-stamp": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=" }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "dev": true + }, "timers-browserify": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", @@ -21024,12 +23345,6 @@ "integrity": "sha1-YaajIBBiKvoHljvzJSA88SI51gQ=", "dev": true }, - "underscore.string": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", - "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=", - "dev": true - }, "undertaker": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.0.tgz", @@ -21189,23 +23504,17 @@ } } }, + "untildify": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-3.0.2.tgz", + "integrity": "sha1-fx8wIFWz/qDz6B3HjrNnZstl4/E=", + "dev": true + }, "upath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.0.0.tgz", - "integrity": "sha1-tHBrlGHKhHOt+JEz0jVonKF/NlY=", - "dev": true, - "requires": { - "lodash": "3.10.1", - "underscore.string": "2.3.3" - }, - "dependencies": { - "lodash": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", - "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", - "dev": true - } - } + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.0.4.tgz", + "integrity": "sha512-d4SJySNBXDaQp+DPrziv3xGS6w3d2Xt69FijJr86zMPBy23JEloMCEOUBBzuN7xCtjLCnmB9tI/z7SBCahHBOw==", + "dev": true }, "urix": { "version": "0.1.0", @@ -21228,6 +23537,21 @@ } } }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "requires": { + "prepend-http": "2.0.0" + } + }, + "url-to-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", + "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", + "dev": true + }, "use": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/use/-/use-2.0.2.tgz", @@ -21384,6 +23708,12 @@ "dev": true, "optional": true }, + "v8-compile-cache": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-1.1.2.tgz", + "integrity": "sha512-ejdrifsIydN1XDH7EuR2hn8ZrkRKUYF7tUcBjBy/lhrCvs2K+zRlbW9UHc0IQ9RsYFZJFqJrieoIHfkCa0DBRA==", + "dev": true + }, "v8flags": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.0.2.tgz", @@ -21493,9 +23823,9 @@ }, "dependencies": { "clone": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.3.tgz", - "integrity": "sha1-KY1+IjFmD0DAA8LtMUDezz9TCF8=", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", "dev": true }, "clone-stats": { @@ -21504,6 +23834,12 @@ "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", "dev": true }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, "replace-ext": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", @@ -21516,7 +23852,7 @@ "integrity": "sha1-XIgDbPVl5d8FVYv8kR+GVt8hiIQ=", "dev": true, "requires": { - "clone": "1.0.3", + "clone": "1.0.4", "clone-stats": "0.0.1", "replace-ext": "0.0.1" } @@ -21858,9 +24194,9 @@ } }, "web3-provider-engine": { - "version": "13.6.0", - "resolved": "https://registry.npmjs.org/web3-provider-engine/-/web3-provider-engine-13.6.0.tgz", - "integrity": "sha512-iCsAlAeLWHxgx6EXuBm5GNg5VBqKtzmnrhEOfJBv8Cetukush7yOvo4RPjDZIynKxg9jfAlMmWqCk6wLxA6coQ==", + "version": "13.8.0", + "resolved": "https://registry.npmjs.org/web3-provider-engine/-/web3-provider-engine-13.8.0.tgz", + "integrity": "sha512-fZXhX5VWwWpoFfrfocslyg6P7cN3YWPG/ASaevNfeO80R+nzgoPUBXcWQekSGSsNDkeRTis4aMmpmofYf1TNtQ==", "requires": { "async": "2.6.0", "clone": "2.1.1", @@ -21868,7 +24204,7 @@ "eth-sig-util": "1.4.2", "ethereumjs-block": "1.7.0", "ethereumjs-tx": "1.3.3", - "ethereumjs-util": "5.1.4", + "ethereumjs-util": "5.1.5", "ethereumjs-vm": "2.3.2", "fetch-ponyfill": "4.1.0", "json-rpc-error": "2.0.0", @@ -21877,16 +24213,16 @@ "readable-stream": "2.3.3", "request": "2.83.0", "semaphore": "1.1.0", - "solc": "0.4.20", + "solc": "0.4.21", "tape": "4.8.0", "xhr": "2.4.1", "xtend": "4.0.1" }, "dependencies": { "ethereumjs-util": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.1.4.tgz", - "integrity": "sha512-wbeTc5prEzIWFSQUcEsCAZbqubtJKy6yS+oZMY1cGG6GLYzLjm4YhC2RNrWIg8hRYnclWpnZmx2zkiufQkmd3w==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.1.5.tgz", + "integrity": "sha512-xPaSEATYJpMTCGowIt0oMZwFP4R1bxd6QsWgkcDvFL0JtXsr39p32WEcD14RscCjfP41YXZPCVWA4yAg0nrJmw==", "requires": { "bn.js": "4.11.8", "create-hash": "1.1.3", @@ -22028,6 +24364,406 @@ } } }, + "webpack-addons": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/webpack-addons/-/webpack-addons-1.1.5.tgz", + "integrity": "sha512-MGO0nVniCLFAQz1qv22zM02QPjcpAoJdy7ED0i3Zy7SY1IecgXCm460ib7H/Wq7e9oL5VL6S2BxaObxwIcag0g==", + "dev": true, + "requires": { + "jscodeshift": "0.4.1" + }, + "dependencies": { + "ansi-styles": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", + "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=", + "dev": true + }, + "ast-types": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.10.1.tgz", + "integrity": "sha512-UY7+9DPzlJ9VM8eY0b2TUZcZvF+1pO0hzMtAyjBYKhOmnvRlqYNYnWdtsMj0V16CGaMlpL0G1jnLbLo4AyotuQ==", + "dev": true + }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "chalk": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", + "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", + "dev": true, + "requires": { + "ansi-styles": "1.0.0", + "has-color": "0.1.7", + "strip-ansi": "0.1.1" + } + }, + "colors": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.2.1.tgz", + "integrity": "sha512-s8+wktIuDSLffCywiwSxQOMqtPxML11a/dtHE17tMn4B1MSWw/C22EKf7M2KGUBcDaVFEGT+S8N02geDXeuNKg==", + "dev": true + }, + "jscodeshift": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.4.1.tgz", + "integrity": "sha512-iOX6If+hsw0q99V3n31t4f5VlD1TQZddH08xbT65ZqA7T4Vkx68emrDZMUOLVvCEAJ6NpAk7DECe3fjC/t52AQ==", + "dev": true, + "requires": { + "async": "1.5.2", + "babel-plugin-transform-flow-strip-types": "6.22.0", + "babel-preset-es2015": "6.24.1", + "babel-preset-stage-1": "6.24.1", + "babel-register": "6.26.0", + "babylon": "6.18.0", + "colors": "1.2.1", + "flow-parser": "0.69.0", + "lodash": "4.17.4", + "micromatch": "2.3.11", + "node-dir": "0.1.8", + "nomnom": "1.8.1", + "recast": "0.12.9", + "temp": "0.8.3", + "write-file-atomic": "1.3.4" + } + }, + "nomnom": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/nomnom/-/nomnom-1.8.1.tgz", + "integrity": "sha1-IVH3Ikcrp55Qp2/BJbuMjy5Nwqc=", + "dev": true, + "requires": { + "chalk": "0.4.0", + "underscore": "1.6.0" + } + }, + "recast": { + "version": "0.12.9", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.12.9.tgz", + "integrity": "sha512-y7ANxCWmMW8xLOaiopiRDlyjQ9ajKRENBH+2wjntIbk3A6ZR1+BLQttkmSHMY7Arl+AAZFwJ10grg2T6f1WI8A==", + "dev": true, + "requires": { + "ast-types": "0.10.1", + "core-js": "2.5.3", + "esprima": "4.0.0", + "private": "0.1.8", + "source-map": "0.6.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "strip-ansi": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", + "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=", + "dev": true + }, + "underscore": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.6.0.tgz", + "integrity": "sha1-izixDKze9jM3uLJOT/htRa6lKag=", + "dev": true + } + } + }, + "webpack-cli": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-2.0.13.tgz", + "integrity": "sha512-0lnOi3yla8FsZVuMsbfnNRB/8DlfuDugKdekC+4ykydZG0+UOidMi5J5LLWN4c0VJ8PqC19yMXXkYyCq78OuqA==", + "dev": true, + "requires": { + "chalk": "2.3.2", + "cross-spawn": "6.0.5", + "diff": "3.5.0", + "enhanced-resolve": "4.0.0", + "glob-all": "3.1.0", + "global-modules": "1.0.0", + "got": "8.3.0", + "inquirer": "5.2.0", + "interpret": "1.1.0", + "jscodeshift": "0.5.0", + "listr": "0.13.0", + "loader-utils": "1.1.0", + "lodash": "4.17.5", + "log-symbols": "2.2.0", + "mkdirp": "0.5.1", + "p-each-series": "1.0.0", + "p-lazy": "1.0.0", + "prettier": "1.11.1", + "resolve-cwd": "2.0.0", + "supports-color": "5.3.0", + "v8-compile-cache": "1.1.2", + "webpack-addons": "1.1.5", + "yargs": "11.0.0", + "yeoman-environment": "2.0.6", + "yeoman-generator": "2.0.3" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "chalk": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", + "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.3.0" + } + }, + "cliui": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.0.0.tgz", + "integrity": "sha512-nY3W5Gu2racvdDk//ELReY+dHjb9PlIcVDFXP72nVIhq2Gy3LuVXYwJoPVudwQnv1shtohpgkdCKT2YaKY0CKw==", + "dev": true, + "requires": { + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "wrap-ansi": "2.1.0" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "1.0.4", + "path-key": "2.0.1", + "semver": "5.5.0", + "shebang-command": "1.2.0", + "which": "1.3.0" + } + }, + "diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true + }, + "enhanced-resolve": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.0.0.tgz", + "integrity": "sha512-jox/62b2GofV1qTUQTMPEJSDIGycS43evqYzD/KVtEb9OCoki9cnacUPxCrZa7JfPzZSYOCZhu9O9luaMxAX8g==", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "memory-fs": "0.4.1", + "tapable": "1.0.0" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + }, + "dependencies": { + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "4.1.1", + "shebang-command": "1.2.0", + "which": "1.3.0" + } + } + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "inquirer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-5.2.0.tgz", + "integrity": "sha512-E9BmnJbAKLPGonz0HeWHtbKf+EeSP93paWO3ZYoUpq/aowXvYGjjCSuashhXPpzbArIjBbji39THkxTz9ZeEUQ==", + "dev": true, + "requires": { + "ansi-escapes": "3.0.0", + "chalk": "2.3.2", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.1.0", + "figures": "2.0.0", + "lodash": "4.17.5", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rxjs": "5.5.8", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "loader-utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", + "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", + "dev": true, + "requires": { + "big.js": "3.2.0", + "emojis-list": "2.1.0", + "json5": "0.5.1" + } + }, + "lodash": { + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", + "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==", + "dev": true + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "2.3.2" + } + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" + } + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + }, + "supports-color": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", + "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + }, + "tapable": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.0.0.tgz", + "integrity": "sha512-dQRhbNQkRnaqauC7WqSJ21EEksgT0fYZX2lqXzGkpo8JNig9zGZTYoMGvyI2nWmXlE2VSVXVDu7wLVGu/mQEsg==", + "dev": true + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "yargs": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.0.0.tgz", + "integrity": "sha512-Rjp+lMYQOWtgqojx1dEWorjCofi1YN7AoFvYV7b1gx/7dAAeuI4kN5SZiEvr0ZmsZTOpDRcCqrpI10L31tFkBw==", + "dev": true, + "requires": { + "cliui": "4.0.0", + "decamelize": "1.2.0", + "find-up": "2.1.0", + "get-caller-file": "1.0.2", + "os-locale": "2.1.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "9.0.2" + } + }, + "yargs-parser": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", + "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", + "dev": true, + "requires": { + "camelcase": "4.1.0" + } + } + } + }, "webpack-sources": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.1.0.tgz", @@ -22180,6 +24916,17 @@ "mkdirp": "0.5.1" } }, + "write-file-atomic": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz", + "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "imurmurhash": "0.1.4", + "slide": "1.1.6" + } + }, "write-file-stdout": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/write-file-stdout/-/write-file-stdout-0.0.2.tgz", @@ -22243,6 +24990,22 @@ "integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU=", "dev": true }, + "xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "dev": true, + "requires": { + "sax": "1.2.4", + "xmlbuilder": "9.0.7" + } + }, + "xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "dev": true + }, "xmldom": { "version": "0.1.27", "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", @@ -22310,6 +25073,15 @@ "camelcase": "3.0.0" } }, + "yauzl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", + "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", + "dev": true, + "requires": { + "fd-slicer": "1.0.1" + } + }, "yazl": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.4.3.tgz", @@ -22324,6 +25096,293 @@ "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", "dev": true + }, + "yeoman-environment": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-2.0.6.tgz", + "integrity": "sha512-jzHBTTy8EPI4ImV8dpUMt+Q5zELkSU5xvGpndHcHudQ4tqN6YgIWaCGmRFl+HDchwRUkcgyjQ+n6/w5zlJBCPg==", + "dev": true, + "requires": { + "chalk": "2.3.2", + "debug": "3.1.0", + "diff": "3.3.1", + "escape-string-regexp": "1.0.5", + "globby": "6.1.0", + "grouped-queue": "0.3.3", + "inquirer": "3.3.0", + "is-scoped": "1.0.0", + "lodash": "4.17.4", + "log-symbols": "2.2.0", + "mem-fs": "1.1.3", + "text-table": "0.2.0", + "untildify": "3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "chalk": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", + "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.3.0" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "2.3.2" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "supports-color": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", + "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "yeoman-generator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/yeoman-generator/-/yeoman-generator-2.0.3.tgz", + "integrity": "sha512-mODmrZ26a94djmGZZuIiomSGlN4wULdou29ZwcySupb2e9FdvoCl7Ps2FqHFjEHio3kOl/iBeaNqrnx3C3NwWg==", + "dev": true, + "requires": { + "async": "2.6.0", + "chalk": "2.3.2", + "cli-table": "0.3.1", + "cross-spawn": "5.1.0", + "dargs": "5.1.0", + "dateformat": "3.0.3", + "debug": "3.1.0", + "detect-conflict": "1.0.1", + "error": "7.0.2", + "find-up": "2.1.0", + "github-username": "4.1.0", + "istextorbinary": "2.2.1", + "lodash": "4.17.4", + "make-dir": "1.2.0", + "mem-fs-editor": "3.0.2", + "minimist": "1.2.0", + "pretty-bytes": "4.0.2", + "read-chunk": "2.1.0", + "read-pkg-up": "3.0.0", + "rimraf": "2.6.2", + "run-async": "2.3.0", + "shelljs": "0.8.1", + "text-table": "0.2.0", + "through2": "2.0.3", + "yeoman-environment": "2.0.6" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "binaryextensions": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.1.1.tgz", + "integrity": "sha512-XBaoWE9RW8pPdPQNibZsW2zh8TW6gcarXp1FZPwT8Uop8ScSNldJEWf2k9l3HeTqdrEwsOsFcq74RiJECW34yA==", + "dev": true + }, + "chalk": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", + "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.3.0" + } + }, + "dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "istextorbinary": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.2.1.tgz", + "integrity": "sha512-TS+hoFl8Z5FAFMK38nhBkdLt44CclNRgDHWeMgsV8ko3nDlr/9UI2Sf839sW7enijf8oKsZYXRvM8g0it9Zmcw==", + "dev": true, + "requires": { + "binaryextensions": "2.1.1", + "editions": "1.3.4", + "textextensions": "2.2.0" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "4.0.0", + "pify": "3.0.0", + "strip-bom": "3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "1.3.1", + "json-parse-better-errors": "1.0.2" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "3.0.0" + } + }, + "pretty-bytes": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-4.0.2.tgz", + "integrity": "sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "4.0.0", + "normalize-package-data": "2.4.0", + "path-type": "3.0.0" + } + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "requires": { + "find-up": "2.1.0", + "read-pkg": "3.0.0" + } + }, + "shelljs": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.1.tgz", + "integrity": "sha512-YA/iYtZpzFe5HyWVGrb02FjPxc4EMCfpoU/Phg9fQoyMC72u9598OUBrsU8IrtwAKG0tO8IYaqbaLIw+k3IRGA==", + "dev": true, + "requires": { + "glob": "7.1.2", + "interpret": "1.1.0", + "rechoir": "0.6.2" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "supports-color": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", + "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "dev": true, + "requires": { + "has-flag": "3.0.0" + } + }, + "textextensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-2.2.0.tgz", + "integrity": "sha512-j5EMxnryTvKxwH2Cq+Pb43tsf6sdEgw6Pdwxk83mPaq0ToeFJt6WE4J3s5BqY7vmjlLgkgXvhtXUxo80FyBhCA==", + "dev": true + } + } } } } diff --git a/package.json b/package.json index ac4758f57..310e357ca 100644 --- a/package.json +++ b/package.json @@ -4,40 +4,39 @@ "public": false, "private": true, "scripts": { - "start": "npm run dev", - "dev": "gulp dev --debug", - "ui": "npm run test:flat:build:states && beefy development/ui-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./", - "mock": "beefy development/mock-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./", - "watch": "mocha watch --recursive \"test/unit/**/*.js\"", - "mascara": "gulp build && cross-env METAMASK_DEBUG=true node ./mascara/example/server", - "dist": "npm run dist:clear && npm install && gulp dist", - "dist:clear": "rm -rf node_modules/eth-contract-metadata && rm -rf node_modules/eth-phishing-detect", + "start": "gulp dev:extension", + "mascara": "gulp dev:mascara & node ./mascara/example/server", + "dist": "gulp dist", "test": "npm run test:unit && npm run test:integration && npm run lint", "test:unit": "cross-env METAMASK_ENV=test mocha --exit --require babel-core/register --require test/helper.js --recursive \"test/unit/**/*.js\"", "test:single": "cross-env METAMASK_ENV=test mocha --require test/helper.js", "test:integration": "npm run test:integration:build && npm run test:flat && npm run test:mascara", "test:integration:build": "gulp build:scss", + "test:e2e": "shell-parallel -s 'npm run ganache:start' -x 'sleep 3 && npm run test:e2e:run'", + "test:e2e:run": "mocha test/e2e/metamask.spec --recursive", + "test:screens": "shell-parallel -s 'npm run ganache:start' -x 'sleep 3 && npm run test:screens:run'", + "test:screens:run": "node test/screens/new-ui.js", "test:coverage": "nyc npm run test:unit && npm run test:coveralls-upload", "test:coveralls-upload": "if [ $COVERALLS_REPO_TOKEN ]; then nyc report --reporter=text-lcov | coveralls; fi", "test:flat": "npm run test:flat:build && karma start test/flat.conf.js", - "test:flat:build": "npm run test:flat:build:ui && npm run test:flat:build:tests", + "test:flat:build": "npm run test:flat:build:ui && npm run test:flat:build:tests && npm run test:flat:build:locales", "test:flat:build:tests": "node test/integration/index.js", "test:flat:build:states": "node development/genStates.js", + "test:flat:build:locales": "mkdirp dist/chrome && cp -R app/_locales dist/chrome/_locales", "test:flat:build:ui": "npm run test:flat:build:states && browserify ./development/mock-dev.js -o ./development/bundle.js", "test:mascara": "npm run test:mascara:build && karma start test/mascara.conf.js", - "test:mascara:build": "mkdirp dist/mascara && npm run test:mascara:build:ui && npm run test:mascara:build:background && npm run test:mascara:build:tests", + "test:mascara:build": "mkdirp dist/mascara && npm run test:mascara:build:ui && npm run test:mascara:build:background && npm run test:mascara:build:tests && npm run test:mascara:build:locales", "test:mascara:build:ui": "browserify mascara/test/test-ui.js -o dist/mascara/ui.js", + "test:mascara:build:locales": "mkdirp dist/chrome && cp -R app/_locales dist/chrome/_locales", "test:mascara:build:background": "browserify mascara/src/background.js -o dist/mascara/background.js", "test:mascara:build:tests": "browserify test/integration/lib/first-time.js -o dist/mascara/tests.js", - "sentry": "export RELEASE=`cat app/manifest.json| jq -r .version` && npm run sentry:release && npm run sentry:upload", - "sentry:release": "npm run sentry:release:new && npm run sentry:release:clean", - "sentry:release:new": "sentry-cli releases --org 'metamask' --project 'metamask' new $RELEASE", - "sentry:release:clean": "sentry-cli releases --org 'metamask' --project 'metamask' files $RELEASE delete --all", - "sentry:upload": "npm run sentry:upload:source && npm run sentry:upload:maps", - "sentry:upload:source": "for FILEPATH in ./dist/chrome/scripts/*.js; do [ -e $FILEPATH ] || continue; export FILE=`basename $FILEPATH` && echo uploading $FILE && sentry-cli releases --org 'metamask' --project 'metamask' files $RELEASE upload $FILEPATH metamask/scripts/$FILE; done;", - "sentry:upload:maps": "sentry-cli releases --org 'metamask' --project 'metamask' files $RELEASE upload-sourcemaps ./dist/sourcemaps/ --url-prefix 'sourcemaps' --rewrite", + "ganache:start": "ganache-cli -m 'phrase upgrade clock rough situate wedding elder clever doctor stamp excess tent'", + "sentry:publish": "node ./development/sentry-publish.js", "lint": "gulp lint", "lint:fix": "gulp lint:fix", + "ui": "npm run test:flat:build:states && beefy development/ui-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./", + "mock": "beefy development/mock-dev.js:bundle.js --live --open --index=./development/index.html --cwd ./", + "watch": "mocha watch --recursive \"test/unit/**/*.js\"", "disc": "gulp disc --debug", "announce": "node development/announcer.js", "version:bump": "node development/run-version-bump.js", @@ -56,7 +55,6 @@ } ], "reactify", - "envify", "brfs" ] }, @@ -75,7 +73,6 @@ "browserify-derequire": "^0.9.4", "browserify-unibabel": "^3.0.0", "classnames": "^2.2.5", - "client-sw-ready-event": "^3.3.0", "clone": "^2.1.1", "copy-to-clipboard": "^3.0.8", "debounce": "^1.0.0", @@ -106,7 +103,7 @@ "ethjs": "^0.2.8", "ethjs-contract": "^0.1.9", "ethjs-ens": "^2.0.0", - "ethjs-query": "^0.3.1", + "ethjs-query": "^0.3.4", "express": "^4.15.5", "extension-link-enabler": "^1.0.0", "extensionizer": "^1.0.0", @@ -115,6 +112,7 @@ "fuse.js": "^3.2.0", "gulp": "github:gulpjs/gulp#4.0", "gulp-autoprefixer": "^5.0.0", + "gulp-debug": "^3.2.0", "gulp-eslint": "^4.0.0", "gulp-sass": "^3.1.0", "hat": "0.0.3", @@ -139,8 +137,8 @@ "number-to-bn": "^1.7.0", "obj-multiplex": "^1.0.0", "obs-store": "^3.0.0", - "once": "^1.3.3", "percentile": "^1.2.0", + "pify": "^3.0.0", "ping-pong-stream": "^1.0.0", "pojo-migrator": "^2.1.0", "polyfill-crypto.getrandomvalues": "^1.0.0", @@ -176,13 +174,14 @@ "semaphore": "^1.0.5", "semver": "^5.4.1", "shallow-copy": "0.0.1", - "sw-stream": "^2.0.0", + "sw-controller": "^1.0.3", + "sw-stream": "^2.0.2", "textarea-caret": "^3.0.1", "through2": "^2.0.3", "valid-url": "^1.0.9", "vreme": "^3.0.2", "web3": "^0.20.1", - "web3-provider-engine": "^13.5.6", + "web3-provider-engine": "^13.8.0", "web3-stream-provider": "^3.0.1", "xtend": "^4.0.1" }, @@ -201,6 +200,7 @@ "brfs": "^1.4.3", "browserify": "^16.1.1", "chai": "^4.1.0", + "chromedriver": "^2.34.1", "compression": "^1.7.1", "coveralls": "^3.0.0", "cross-env": "^5.1.4", @@ -210,16 +210,19 @@ "enzyme": "^3.3.0", "enzyme-adapter-react-15": "^1.0.5", "eslint-plugin-chai": "0.0.1", - "eslint-plugin-mocha": "^4.9.0", + "eslint-plugin-json": "^1.2.0", + "eslint-plugin-mocha": "^5.0.0", "eslint-plugin-react": "^7.4.0", "eth-json-rpc-middleware": "^1.2.7", "fs-promise": "^2.0.3", + "ganache-cli": "^6.1.0", + "gifencoder": "^1.1.0", "gulp": "github:gulpjs/gulp#6d71a658c61edb3090221579d8f97dbe086ba2ed", "gulp-babel": "^7.0.0", "gulp-eslint": "^4.0.0", - "gulp-if": "^2.0.2", "gulp-json-editor": "^2.2.1", "gulp-livereload": "^3.8.1", + "gulp-multi-process": "^1.3.1", "gulp-replace": "^0.6.1", "gulp-sourcemaps": "^2.6.0", "gulp-stylefmt": "^1.1.0", @@ -229,8 +232,9 @@ "gulp-util": "^3.0.7", "gulp-watch": "^5.0.0", "gulp-zip": "^4.0.0", + "image-size": "^0.6.2", "isomorphic-fetch": "^2.2.1", - "jsdom": "^11.1.0", + "jsdom": "^11.2.0", "jsdom-global": "^3.0.2", "jshint-stylish": "~2.2.1", "karma": "^2.0.0", @@ -247,6 +251,7 @@ "node-sass": "^4.7.2", "nyc": "^11.0.3", "open": "0.0.5", + "png-file-stream": "^1.0.0", "prompt": "^1.0.0", "qs": "^6.2.0", "qunitjs": "^2.4.1", @@ -254,11 +259,14 @@ "react-test-renderer": "^15.6.2", "react-testutils-additions": "^15.2.0", "redux-test-utils": "^0.2.2", - "sinon": "^4.0.0", + "rimraf": "^2.6.2", + "selenium-webdriver": "^3.5.0", + "shell-parallel": "^1.0.3", + "sinon": "^5.0.0", "stylelint-config-standard": "^18.2.0", "tape": "^4.5.1", "testem": "^2.0.0", - "uglifyify": "^4.0.2", + "uglifyify": "^4.0.5", "vinyl-buffer": "^1.0.1", "vinyl-source-stream": "^2.0.0", "watchify": "^3.9.0" diff --git a/test/base.conf.js b/test/base.conf.js index adb5357e8..e2e9d44ba 100644 --- a/test/base.conf.js +++ b/test/base.conf.js @@ -19,11 +19,13 @@ module.exports = function(config) { 'test/integration/jquery-3.1.0.min.js', { pattern: 'dist/chrome/images/**/*.*', watched: false, included: false, served: true }, { pattern: 'dist/chrome/fonts/**/*.*', watched: false, included: false, served: true }, + { pattern: 'dist/chrome/_locales/**/*.*', watched: false, included: false, served: true }, ], proxies: { '/images/': '/base/dist/chrome/images/', '/fonts/': '/base/dist/chrome/fonts/', + '/_locales/': '/base/dist/chrome/_locales/', }, // test results reporter to use diff --git a/test/e2e/func.js b/test/e2e/func.js new file mode 100644 index 000000000..733225565 --- /dev/null +++ b/test/e2e/func.js @@ -0,0 +1,18 @@ +require('chromedriver') +const webdriver = require('selenium-webdriver') + +exports.delay = function delay (time) { + return new Promise(resolve => setTimeout(resolve, time)) +} + + +exports.buildWebDriver = function buildWebDriver (extPath) { + return new webdriver.Builder() + .withCapabilities({ + chromeOptions: { + args: [`load-extension=${extPath}`], + }, + }) + .forBrowser('chrome') + .build() +} diff --git a/test/e2e/metamask.spec.js b/test/e2e/metamask.spec.js new file mode 100644 index 000000000..e0ff2a57e --- /dev/null +++ b/test/e2e/metamask.spec.js @@ -0,0 +1,145 @@ +const fs = require('fs') +const mkdirp = require('mkdirp') +const path = require('path') +const assert = require('assert') +const pify = require('pify') +const webdriver = require('selenium-webdriver') +const By = webdriver.By +const { delay, buildWebDriver } = require('./func') + +describe('Metamask popup page', function () { + let driver + this.seedPhase + this.accountAddress + this.timeout(0) + + before(async function () { + const extPath = path.resolve('dist/chrome') + driver = buildWebDriver(extPath) + await driver.get('chrome://extensions-frame') + const elems = await driver.findElements(By.css('.extension-list-item-wrapper')) + const extensionId = await elems[1].getAttribute('id') + await driver.get(`chrome-extension://${extensionId}/popup.html`) + await delay(500) + }) + + afterEach(async function () { + if (this.currentTest.state === 'failed') { + await verboseReportOnFailure(this.currentTest) + } + }) + + after(async function () { + await driver.quit() + }) + + describe('#onboarding', () => { + it('should open Metamask.io', async function () { + const tabs = await driver.getAllWindowHandles() + await driver.switchTo().window(tabs[0]) + await delay(300) + await setProviderType('localhost') + await delay(300) + }) + + it('should match title', async () => { + const title = await driver.getTitle() + assert.equal(title, 'MetaMask', 'title matches MetaMask') + }) + + it('should show privacy notice', async () => { + const privacy = await driver.findElement(By.css('.terms-header')).getText() + assert.equal(privacy, 'PRIVACY NOTICE', 'shows privacy notice') + driver.findElement(By.css('button')).click() + await delay(300) + }) + + it('should show terms of use', async () => { + await delay(300) + const terms = await driver.findElement(By.css('.terms-header')).getText() + assert.equal(terms, 'TERMS OF USE', 'shows terms of use') + await delay(300) + }) + + it('should be unable to continue without scolling throught the terms of use', async () => { + const button = await driver.findElement(By.css('button')).isEnabled() + assert.equal(button, false, 'disabled continue button') + const element = driver.findElement(By.linkText( + 'Attributions' + )) + await driver.executeScript('arguments[0].scrollIntoView(true)', element) + await delay(300) + }) + + it('should be able to continue when scrolled to the bottom of terms of use', async () => { + const button = await driver.findElement(By.css('button')) + const buttonEnabled = await button.isEnabled() + await delay(500) + assert.equal(buttonEnabled, true, 'enabled continue button') + await button.click() + await delay(300) + }) + + it('should accept password with length of eight', async () => { + const passwordBox = await driver.findElement(By.id('password-box')) + const passwordBoxConfirm = await driver.findElement(By.id('password-box-confirm')) + const button = driver.findElement(By.css('button')) + + passwordBox.sendKeys('123456789') + passwordBoxConfirm.sendKeys('123456789') + await delay(500) + await button.click() + }) + + it('should show value was created and seed phrase', async () => { + await delay(700) + this.seedPhase = await driver.findElement(By.css('.twelve-word-phrase')).getText() + const continueAfterSeedPhrase = await driver.findElement(By.css('button')) + await continueAfterSeedPhrase.click() + await delay(300) + }) + + it('should show lock account', async () => { + await driver.findElement(By.css('.sandwich-expando')).click() + await delay(500) + await driver.findElement(By.css('#app-content > div > div:nth-child(3) > span > div > li:nth-child(3)')).click() + }) + + it('should accept account password after lock', async () => { + await delay(500) + await driver.findElement(By.id('password-box')).sendKeys('123456789') + await driver.findElement(By.css('button')).click() + await delay(500) + }) + + it('should show QR code option', async () => { + await delay(300) + await driver.findElement(By.css('.fa-ellipsis-h')).click() + await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div > div:nth-child(1) > flex-column > div.name-label > div > span > i > div > div > li:nth-child(3)')).click() + await delay(300) + }) + + it('should show the account address', async () => { + this.accountAddress = await driver.findElement(By.css('.ellip-address')).getText() + await driver.findElement(By.css('.fa-arrow-left')).click() + await delay(500) + }) + }) + + async function setProviderType(type) { + await driver.executeScript('window.metamask.setProviderType(arguments[0])', type) + } + + async function verboseReportOnFailure(test) { + const artifactDir = `./test-artifacts/${test.title}` + const filepathBase = `${artifactDir}/test-failure` + await pify(mkdirp)(artifactDir) + // capture screenshot + const screenshot = await driver.takeScreenshot() + await pify(fs.writeFile)(`${filepathBase}-screenshot.png`, screenshot, { encoding: 'base64' }) + // capture dom source + const htmlSource = await driver.getPageSource() + await pify(fs.writeFile)(`${filepathBase}-dom.html`, htmlSource) + } + +}) diff --git a/test/integration/lib/add-token.js b/test/integration/lib/add-token.js index cc04beb21..1840bdd39 100644 --- a/test/integration/lib/add-token.js +++ b/test/integration/lib/add-token.js @@ -75,7 +75,7 @@ async function runAddTokenFlowTest (assert, done) { // Confirm Add token assert.equal( $('.add-token__description')[0].textContent, - 'Would you like to add these tokens?', + 'Token balance(s)', 'confirm add token rendered' ) assert.ok($('button.btn-primary--lg')[0], 'confirm add token button found') diff --git a/test/integration/lib/tx-list-items.js b/test/integration/lib/tx-list-items.js new file mode 100644 index 000000000..d0056eb94 --- /dev/null +++ b/test/integration/lib/tx-list-items.js @@ -0,0 +1,61 @@ +const reactTriggerChange = require('../../lib/react-trigger-change') +const { + timeout, + queryAsync, + findAsync, +} = require('../../lib/util') + +QUnit.module('tx list items') + +QUnit.test('renders list items successfully', (assert) => { + const done = assert.async() + runTxListItemsTest(assert).then(done).catch((err) => { + assert.notOk(err, `Error was thrown: ${err.stack}`) + done() + }) +}) + +async function runTxListItemsTest(assert, done) { + console.log('*** start runTxListItemsTest') + const selectState = await queryAsync($, 'select') + selectState.val('tx list items') + reactTriggerChange(selectState[0]) + + const metamaskLogo = await queryAsync($, '.left-menu-wrapper') + assert.ok(metamaskLogo[0], 'metamask logo present') + metamaskLogo[0].click() + + const txListItems = await queryAsync($, '.tx-list-item') + assert.equal(txListItems.length, 8, 'all tx list items are rendered') + + const unapprovedTx = txListItems[0] + assert.equal($(unapprovedTx).hasClass('tx-list-pending-item-container'), true, 'unapprovedTx has the correct class') + + const retryTx = txListItems[1] + const retryTxLink = await findAsync($(retryTx), '.tx-list-item-retry-link') + assert.equal(retryTxLink[0].textContent, 'Increase the gas price on your transaction', 'retryTx has expected link') + + const approvedTx = txListItems[2] + const approvedTxRenderedStatus = await findAsync($(approvedTx), '.tx-list-status') + assert.equal(approvedTxRenderedStatus[0].textContent, 'Approved', 'approvedTx has correct label') + + const unapprovedMsg = txListItems[3] + const unapprovedMsgDescription = await findAsync($(unapprovedMsg), '.tx-list-account') + assert.equal(unapprovedMsgDescription[0].textContent, 'Signature Request', 'unapprovedMsg has correct description') + + const failedTx = txListItems[4] + const failedTxRenderedStatus = await findAsync($(failedTx), '.tx-list-status') + assert.equal(failedTxRenderedStatus[0].textContent, 'Failed', 'failedTx has correct label') + + const shapeShiftTx = txListItems[5] + const shapeShiftTxStatus = await findAsync($(shapeShiftTx), '.flex-column div:eq(1)') + assert.equal(shapeShiftTxStatus[0].textContent, 'No deposits received', 'shapeShiftTx has correct status') + + const confirmedTokenTx = txListItems[6] + const confirmedTokenTxAddress = await findAsync($(confirmedTokenTx), '.tx-list-account') + assert.equal(confirmedTokenTxAddress[0].textContent, '0xe7884118...81a9', 'confirmedTokenTx has correct address') + + const rejectedTx = txListItems[7] + const rejectedTxRenderedStatus = await findAsync($(rejectedTx), '.tx-list-status') + assert.equal(rejectedTxRenderedStatus[0].textContent, 'Rejected', 'rejectedTx has correct label') +} diff --git a/test/screens/func.js b/test/screens/func.js new file mode 100644 index 000000000..733225565 --- /dev/null +++ b/test/screens/func.js @@ -0,0 +1,18 @@ +require('chromedriver') +const webdriver = require('selenium-webdriver') + +exports.delay = function delay (time) { + return new Promise(resolve => setTimeout(resolve, time)) +} + + +exports.buildWebDriver = function buildWebDriver (extPath) { + return new webdriver.Builder() + .withCapabilities({ + chromeOptions: { + args: [`load-extension=${extPath}`], + }, + }) + .forBrowser('chrome') + .build() +} diff --git a/test/screens/new-ui.js b/test/screens/new-ui.js new file mode 100644 index 000000000..91b3a9633 --- /dev/null +++ b/test/screens/new-ui.js @@ -0,0 +1,230 @@ +const path = require('path') +const fs = require('fs') +const pify = require('pify') +const mkdirp = require('mkdirp') +const rimraf = require('rimraf') +const webdriver = require('selenium-webdriver') +const endOfStream = require('end-of-stream') +const GIFEncoder = require('gifencoder') +const pngFileStream = require('png-file-stream') +const sizeOfPng = require('image-size/lib/types/png') +const By = webdriver.By +const { delay, buildWebDriver } = require('./func') +const localesIndex = require('../../app/_locales/index.json') + +let driver + +captureAllScreens().catch((err) => { + try { + console.error(err) + verboseReportOnFailure() + driver.quit() + } catch (err) { + console.error(err) + } + process.exit(1) +}) + +async function captureAllScreens() { + let screenshotCount = 0 + + // common names + let button + let tabs + let element + + await cleanScreenShotDir() + + // setup selenium and install extension + const extPath = path.resolve('dist/chrome') + driver = buildWebDriver(extPath) + await driver.get('chrome://extensions-frame') + const elems = await driver.findElements(By.css('.extension-list-item-wrapper')) + const extensionId = await elems[1].getAttribute('id') + await driver.get(`chrome-extension://${extensionId}/home.html`) + await delay(500) + tabs = await driver.getAllWindowHandles() + await driver.switchTo().window(tabs[0]) + await delay(1000) + await setProviderType('localhost') + await delay(300) + + // click try new ui + await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div.flex-row.flex-center.flex-grow > p')).click() + await delay(300) + + // close metamask homepage and extra home.html + tabs = await driver.getAllWindowHandles() + // metamask homepage is opened on prod, not dev + if (tabs.length > 2) { + await driver.switchTo().window(tabs[2]) + driver.close() + } + await driver.switchTo().window(tabs[1]) + driver.close() + await driver.switchTo().window(tabs[0]) + await delay(300) + await captureLanguageScreenShots('welcome-new-ui') + + // setup account + await delay(1000) + await driver.findElement(By.css('body')).click() + await delay(300) + await captureLanguageScreenShots('welcome') + + await driver.findElement(By.css('button')).click() + await captureLanguageScreenShots('create password') + + const passwordBox = await driver.findElement(By.css('input[type=password]:nth-of-type(1)')) + const passwordBoxConfirm = await driver.findElement(By.css('input[type=password]:nth-of-type(2)')) + passwordBox.sendKeys('123456789') + passwordBoxConfirm.sendKeys('123456789') + await delay(500) + await captureLanguageScreenShots('choose-password-filled') + + await driver.findElement(By.css('button')).click() + await delay(500) + await captureLanguageScreenShots('unique account image') + + await driver.findElement(By.css('button')).click() + await delay(500) + await captureLanguageScreenShots('privacy note') + + await driver.findElement(By.css('button')).click() + await delay(300) + await captureLanguageScreenShots('terms') + + await delay(300) + element = driver.findElement(By.linkText('Attributions')) + await driver.executeScript('arguments[0].scrollIntoView(true)', element) + await delay(300) + await captureLanguageScreenShots('terms-scrolled') + + await driver.findElement(By.css('button')).click() + await delay(300) + await captureLanguageScreenShots('secret backup phrase') + + await driver.findElement(By.css('button')).click() + await delay(300) + await captureLanguageScreenShots('secret backup phrase') + + await driver.findElement(By.css('.backup-phrase__reveal-button')).click() + await delay(300) + await captureLanguageScreenShots('secret backup phrase - reveal') + + await driver.findElement(By.css('button')).click() + await delay(300) + await captureLanguageScreenShots('confirm secret backup phrase') + + // finish up + console.log('building gif...') + await generateGif() + await driver.quit() + return + + // + // await button.click() + // await delay(700) + // this.seedPhase = await driver.findElement(By.css('.twelve-word-phrase')).getText() + // await captureScreenShot('seed phrase') + // + // const continueAfterSeedPhrase = await driver.findElement(By.css('button')) + // await continueAfterSeedPhrase.click() + // await delay(300) + // await captureScreenShot('main screen') + // + // await driver.findElement(By.css('.sandwich-expando')).click() + // await delay(500) + // await captureScreenShot('menu') + + // await driver.findElement(By.css('#app-content > div > div:nth-child(3) > span > div > li:nth-child(3)')).click() + // await captureScreenShot('main screen') + // it('should accept account password after lock', async () => { + // await delay(500) + // await driver.findElement(By.id('password-box')).sendKeys('123456789') + // await driver.findElement(By.css('button')).click() + // await delay(500) + // }) + // + // it('should show QR code option', async () => { + // await delay(300) + // await driver.findElement(By.css('.fa-ellipsis-h')).click() + // await driver.findElement(By.css('#app-content > div > div.app-primary.from-right > div > div > div:nth-child(1) > flex-column > div.name-label > div > span > i > div > div > li:nth-child(3)')).click() + // await delay(300) + // }) + // + // it('should show the account address', async () => { + // this.accountAddress = await driver.findElement(By.css('.ellip-address')).getText() + // await driver.findElement(By.css('.fa-arrow-left')).click() + // await delay(500) + // }) + + async function captureLanguageScreenShots(label) { + const nonEnglishLocales = localesIndex.filter(localeMeta => localeMeta.code !== 'en') + // take english shot + await captureScreenShot(`${label} (en)`) + for (let localeMeta of nonEnglishLocales) { + // set locale and take shot + await setLocale(localeMeta.code) + await delay(300) + await captureScreenShot(`${label} (${localeMeta.code})`) + } + // return locale to english + await setLocale('en') + await delay(300) + } + + async function setLocale(code) { + await driver.executeScript('window.metamask.updateCurrentLocale(arguments[0])', code) + } + + async function setProviderType(type) { + await driver.executeScript('window.metamask.setProviderType(arguments[0])', type) + } + + // cleanup + await driver.quit() + + async function cleanScreenShotDir() { + await pify(rimraf)(`./test-artifacts/screens/`) + } + + async function captureScreenShot(label) { + const shotIndex = screenshotCount.toString().padStart(4, '0') + screenshotCount++ + const artifactDir = `./test-artifacts/screens/` + await pify(mkdirp)(artifactDir) + // capture screenshot + const screenshot = await driver.takeScreenshot() + await pify(fs.writeFile)(`${artifactDir}/${shotIndex} - ${label}.png`, screenshot, { encoding: 'base64' }) + } + + async function generateGif(){ + // calculate screenshot size + const screenshot = await driver.takeScreenshot() + const pngBuffer = Buffer.from(screenshot, 'base64') + const size = sizeOfPng.calculate(pngBuffer) + + // read only the english pngs into gif + const encoder = new GIFEncoder(size.width, size.height) + const stream = pngFileStream('./test-artifacts/screens/* (en).png') + .pipe(encoder.createWriteStream({ repeat: 0, delay: 1000, quality: 10 })) + .pipe(fs.createWriteStream('./test-artifacts/screens/walkthrough (en).gif')) + + // wait for end + await pify(endOfStream)(stream) + } + +} + +async function verboseReportOnFailure(test) { + const artifactDir = `./test-artifacts/${test.title}` + const filepathBase = `${artifactDir}/test-failure` + await pify(mkdirp)(artifactDir) + // capture screenshot + const screenshot = await driver.takeScreenshot() + await pify(fs.writeFile)(`${filepathBase}-screenshot.png`, screenshot, { encoding: 'base64' }) + // capture dom source + const htmlSource = await driver.getPageSource() + await pify(fs.writeFile)(`${filepathBase}-dom.html`, htmlSource) +} diff --git a/test/unit/migrations/023-test.js b/test/unit/migrations/023-test.js new file mode 100644 index 000000000..be432d9fa --- /dev/null +++ b/test/unit/migrations/023-test.js @@ -0,0 +1,99 @@ +const assert = require('assert') +const migration23 = require('../../../app/scripts/migrations/023') +const properTime = (new Date()).getTime() +const storage = { + "meta": {}, + "data": { + "TransactionController": { + "transactions": [ + ] + }, + }, +} + +const transactions = [] +const transactions40 = [] +const transactions20 = [] + +const txStates = [ + 'unapproved', + 'approved', + 'signed', + 'submitted', + 'confirmed', + 'rejected', + 'failed', + 'dropped', +] + +const deletableTxStates = [ + 'confirmed', + 'rejected', + 'failed', + 'dropped', +] + +let nonDeletableCount = 0 + +let status +while (transactions.length <= 100) { + status = txStates[Math.floor(Math.random() * Math.floor(txStates.length - 1))] + if (!deletableTxStates.find((s) => s === status)) nonDeletableCount++ + transactions.push({status}) +} + +while (transactions40.length < 40) { + status = txStates[Math.floor(Math.random() * Math.floor(txStates.length - 1))] + transactions40.push({status}) +} + +while (transactions20.length < 20) { + status = txStates[Math.floor(Math.random() * Math.floor(txStates.length - 1))] + transactions20.push({status}) +} + + + +storage.data.TransactionController.transactions = transactions + +describe('storage is migrated successfully and the proper transactions are remove from state', () => { + it('should remove transactions that are unneeded', (done) => { + migration23.migrate(storage) + .then((migratedData) => { + let leftoverNonDeletableTxCount = 0 + const migratedTransactions = migratedData.data.TransactionController.transactions + migratedTransactions.forEach((tx) => { + if (!deletableTxStates.find((s) => s === tx.status)) { + leftoverNonDeletableTxCount++ + } + }) + assert.equal(leftoverNonDeletableTxCount, nonDeletableCount, 'migration shouldnt delete transactions we want to keep') + assert((migratedTransactions.length >= 40), `should be equal or greater to 40 if they are non deletable states got ${migratedTransactions.length} transactions`) + done() + }).catch(done) + }) + + it('should not remove any transactions because 40 is the expectable limit', (done) => { + storage.meta.version = 22 + storage.data.TransactionController.transactions = transactions40 + migration23.migrate(storage) + .then((migratedData) => { + const migratedTransactions = migratedData.data.TransactionController.transactions + + assert.equal(migratedTransactions.length, 40, 'migration shouldnt delete when at limit') + done() + }).catch(done) + }) + + it('should not remove any transactions because 20 txs is under the expectable limit', (done) => { + storage.meta.version = 22 + storage.data.TransactionController.transactions = transactions20 + migration23.migrate(storage) + .then((migratedData) => { + const migratedTransactions = migratedData.data.TransactionController.transactions + assert.equal(migratedTransactions.length, 20, 'migration shouldnt delete when under limit') + done() + }).catch(done) + }) + +}) diff --git a/test/unit/nonce-tracker-test.js b/test/unit/nonce-tracker-test.js index 8970cf84d..5a27882ef 100644 --- a/test/unit/nonce-tracker-test.js +++ b/test/unit/nonce-tracker-test.js @@ -33,6 +33,42 @@ describe('Nonce Tracker', function () { }) }) + describe('sentry issue 476304902', function () { + beforeEach(function () { + const txGen = new MockTxGen() + pendingTxs = txGen.generate({ status: 'submitted' }, { + fromNonce: 3, + count: 29, + }) + nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x3') + }) + + it('should return 9', async function () { + this.timeout(15000) + const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') + assert.equal(nonceLock.nextNonce, '32', `nonce should be 32 got ${nonceLock.nextNonce}`) + await nonceLock.releaseLock() + }) + }) + + describe('issue 3670', function () { + beforeEach(function () { + const txGen = new MockTxGen() + pendingTxs = txGen.generate({ status: 'submitted' }, { + fromNonce: 6, + count: 3, + }) + nonceTracker = generateNonceTrackerWith(pendingTxs, [], '0x6') + }) + + it('should return 9', async function () { + this.timeout(15000) + const nonceLock = await nonceTracker.getNonceLock('0x7d3517b0d011698406d6e0aed8453f0be2697926') + assert.equal(nonceLock.nextNonce, '9', `nonce should be 9 got ${nonceLock.nextNonce}`) + await nonceLock.releaseLock() + }) + }) + describe('with no previous txs', function () { beforeEach(function () { nonceTracker = generateNonceTrackerWith([], []) diff --git a/test/unit/tx-controller-test.js b/test/unit/tx-controller-test.js index 712097fce..6bd010e7a 100644 --- a/test/unit/tx-controller-test.js +++ b/test/unit/tx-controller-test.js @@ -162,7 +162,7 @@ describe('Transaction Controller', function () { describe('#addUnapprovedTransaction', function () { it('should add an unapproved transaction and return a valid txMeta', function (done) { - txController.addUnapprovedTransaction({}) + txController.addUnapprovedTransaction({ from: '0x1678a085c290ebd122dc42cba69373b5953b831d' }) .then((txMeta) => { assert(('id' in txMeta), 'should have a id') assert(('time' in txMeta), 'should have a time stamp') @@ -182,7 +182,7 @@ describe('Transaction Controller', function () { assert(txMetaFromEmit, 'txMeta is falsey') done() }) - txController.addUnapprovedTransaction({}) + txController.addUnapprovedTransaction({ from: '0x1678a085c290ebd122dc42cba69373b5953b831d' }) .catch(done) }) @@ -213,6 +213,7 @@ describe('Transaction Controller', function () { describe('#validateTxParams', function () { it('does not throw for positive values', function (done) { var sample = { + from: '0x1678a085c290ebd122dc42cba69373b5953b831d', value: '0x01', } txController.txGasUtil.validateTxParams(sample).then(() => { @@ -222,6 +223,7 @@ describe('Transaction Controller', function () { it('returns error for negative values', function (done) { var sample = { + from: '0x1678a085c290ebd122dc42cba69373b5953b831d', value: '-0x01', } txController.txGasUtil.validateTxParams(sample) diff --git a/test/unit/tx-gas-util-test.js b/test/unit/tx-gas-util-test.js index d9a12d1c3..15d412c72 100644 --- a/test/unit/tx-gas-util-test.js +++ b/test/unit/tx-gas-util-test.js @@ -29,4 +29,28 @@ describe('Tx Gas Util', function () { } assert.throws(() => { txGasUtil.validateRecipient(zeroRecipientTxParams) }, Error, 'Invalid recipient address') }) + + it('should error when from is not a hex string', function () { + + // where from is undefined + const txParams = {} + assert.throws(() => { txGasUtil.validateFrom(txParams) }, Error, `Invalid from address ${txParams.from} not a string`) + + // where from is array + txParams.from = [] + assert.throws(() => { txGasUtil.validateFrom(txParams) }, Error, `Invalid from address ${txParams.from} not a string`) + + // where from is a object + txParams.from = {} + assert.throws(() => { txGasUtil.validateFrom(txParams) }, Error, `Invalid from address ${txParams.from} not a string`) + + // where from is a invalid address + txParams.from = 'im going to fail' + assert.throws(() => { txGasUtil.validateFrom(txParams) }, Error, `Invalid from address`) + + // should run + txParams.from ='0x1678a085c290ebd122dc42cba69373b5953b831d' + txGasUtil.validateFrom(txParams) + }) + }) diff --git a/test/unit/tx-state-manager-test.js b/test/unit/tx-state-manager-test.js index 220bf501f..a5ac13664 100644 --- a/test/unit/tx-state-manager-test.js +++ b/test/unit/tx-state-manager-test.js @@ -240,12 +240,12 @@ describe('TransactionStateManager', function () { }) describe('#wipeTransactions', function () { - + const specificAddress = '0xaa' const otherAddress = '0xbb' it('should remove only the transactions from a specific address', function () { - + const txMetas = [ { id: 0, status: 'unapproved', txParams: { from: specificAddress, to: otherAddress }, metamaskNetworkId: currentNetworkId }, { id: 1, status: 'confirmed', txParams: { from: otherAddress, to: specificAddress }, metamaskNetworkId: currentNetworkId }, @@ -268,7 +268,7 @@ describe('TransactionStateManager', function () { { id: 1, status: 'confirmed', txParams: { from: specificAddress, to: otherAddress }, metamaskNetworkId: otherNetworkId }, { id: 2, status: 'confirmed', txParams: { from: specificAddress, to: otherAddress }, metamaskNetworkId: otherNetworkId }, ] - + txMetas.forEach((txMeta) => txStateManager.addTx(txMeta, noop)) txStateManager.wipeTransactions(specificAddress) diff --git a/ui/app/accounts/import/index.js b/ui/app/accounts/import/index.js index fc9031a65..52d3dcde9 100644 --- a/ui/app/accounts/import/index.js +++ b/ui/app/accounts/import/index.js @@ -1,43 +1,44 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') +const PropTypes = require('prop-types') const connect = require('react-redux').connect -const t = require('../../../i18n') import Select from 'react-select' // Subviews const JsonImportView = require('./json.js') const PrivateKeyImportView = require('./private-key.js') -const menuItems = [ - t('privateKey'), - t('jsonFile'), -] -module.exports = connect(mapStateToProps)(AccountImportSubview) - -function mapStateToProps (state) { - return { - menuItems, - } +AccountImportSubview.contextTypes = { + t: PropTypes.func, } +module.exports = connect()(AccountImportSubview) + + inherits(AccountImportSubview, Component) function AccountImportSubview () { Component.call(this) } +AccountImportSubview.prototype.getMenuItemTexts = function () { + return [ + this.context.t('privateKey'), + this.context.t('jsonFile'), + ] +} + AccountImportSubview.prototype.render = function () { - const props = this.props const state = this.state || {} - const { menuItems } = props + const menuItems = this.getMenuItemTexts() const { type } = state return ( h('div.new-account-import-form', [ h('.new-account-import-disclaimer', [ - h('span', t('importAccountMsg')), + h('span', this.context.t('importAccountMsg')), h('span', { style: { cursor: 'pointer', @@ -48,12 +49,12 @@ AccountImportSubview.prototype.render = function () { url: 'https://metamask.helpscoutdocs.com/article/17-what-are-loose-accounts', }) }, - }, t('here')), + }, this.context.t('here')), ]), h('div.new-account-import-form__select-section', [ - h('div.new-account-import-form__select-label', t('selectType')), + h('div.new-account-import-form__select-label', this.context.t('selectType')), h(Select, { className: 'new-account-import-form__select', @@ -79,16 +80,15 @@ AccountImportSubview.prototype.render = function () { } AccountImportSubview.prototype.renderImportView = function () { - const props = this.props const state = this.state || {} const { type } = state - const { menuItems } = props + const menuItems = this.getMenuItemTexts() const current = type || menuItems[0] switch (current) { - case t('privateKey'): + case this.context.t('privateKey'): return h(PrivateKeyImportView) - case t('jsonFile'): + case this.context.t('jsonFile'): return h(JsonImportView) default: return h(JsonImportView) diff --git a/ui/app/accounts/import/json.js b/ui/app/accounts/import/json.js index eeba73e77..e53c1c9ca 100644 --- a/ui/app/accounts/import/json.js +++ b/ui/app/accounts/import/json.js @@ -4,7 +4,7 @@ const h = require('react-hyperscript') const connect = require('react-redux').connect const actions = require('../../actions') const FileInput = require('react-simple-file-input').default -const t = require('../../../i18n') + const HELP_LINK = 'https://support.metamask.io/kb/article/7-importing-accounts' @@ -24,11 +24,11 @@ class JsonImportSubview extends Component { return ( h('div.new-account-import-form__json', [ - h('p', t('usedByClients')), + h('p', this.context.t('usedByClients')), h('a.warning', { href: HELP_LINK, target: '_blank', - }, t('fileImportFail')), + }, this.context.t('fileImportFail')), h(FileInput, { readAs: 'text', @@ -43,7 +43,7 @@ class JsonImportSubview extends Component { h('input.new-account-import-form__input-password', { type: 'password', - placeholder: t('enterPassword'), + placeholder: this.context.t('enterPassword'), id: 'json-password-box', onKeyPress: this.createKeyringOnEnter.bind(this), }), @@ -53,13 +53,13 @@ class JsonImportSubview extends Component { h('button.btn-secondary.new-account-create-form__button', { onClick: () => this.props.goHome(), }, [ - t('cancel'), + this.context.t('cancel'), ]), h('button.btn-primary.new-account-create-form__button', { onClick: () => this.createNewKeychain(), }, [ - t('import'), + this.context.t('import'), ]), ]), @@ -84,14 +84,14 @@ class JsonImportSubview extends Component { const state = this.state if (!state) { - const message = t('validFileImport') + const message = this.context.t('validFileImport') return this.props.displayWarning(message) } const { fileContents } = state if (!fileContents) { - const message = t('needImportFile') + const message = this.context.t('needImportFile') return this.props.displayWarning(message) } @@ -99,7 +99,7 @@ class JsonImportSubview extends Component { const password = passwordInput.value if (!password) { - const message = t('needImportPassword') + const message = this.context.t('needImportPassword') return this.props.displayWarning(message) } @@ -112,6 +112,7 @@ JsonImportSubview.propTypes = { goHome: PropTypes.func, displayWarning: PropTypes.func, importNewJsonAccount: PropTypes.func, + t: PropTypes.func, } const mapStateToProps = state => { @@ -128,4 +129,9 @@ const mapDispatchToProps = dispatch => { } } +JsonImportSubview.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(JsonImportSubview) + diff --git a/ui/app/accounts/import/private-key.js b/ui/app/accounts/import/private-key.js index 13c8da722..006131bdc 100644 --- a/ui/app/accounts/import/private-key.js +++ b/ui/app/accounts/import/private-key.js @@ -1,12 +1,17 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') +const PropTypes = require('prop-types') const connect = require('react-redux').connect const actions = require('../../actions') -const t = require('../../../i18n') + +PrivateKeyImportView.contextTypes = { + t: PropTypes.func, +} module.exports = connect(mapStateToProps, mapDispatchToProps)(PrivateKeyImportView) + function mapStateToProps (state) { return { error: state.appState.warning, @@ -34,7 +39,7 @@ PrivateKeyImportView.prototype.render = function () { return ( h('div.new-account-import-form__private-key', [ - h('span.new-account-create-form__instruction', t('pastePrivateKey')), + h('span.new-account-create-form__instruction', this.context.t('pastePrivateKey')), h('div.new-account-import-form__private-key-password-container', [ @@ -51,13 +56,13 @@ PrivateKeyImportView.prototype.render = function () { h('button.btn-secondary--lg.new-account-create-form__button', { onClick: () => goHome(), }, [ - t('cancel'), + this.context.t('cancel'), ]), h('button.btn-primary--lg.new-account-create-form__button', { onClick: () => this.createNewKeychain(), }, [ - t('import'), + this.context.t('import'), ]), ]), diff --git a/ui/app/accounts/import/seed.js b/ui/app/accounts/import/seed.js index 9ffc669a2..d98909baa 100644 --- a/ui/app/accounts/import/seed.js +++ b/ui/app/accounts/import/seed.js @@ -1,11 +1,16 @@ const inherits = require('util').inherits const Component = require('react').Component const h = require('react-hyperscript') +const PropTypes = require('prop-types') const connect = require('react-redux').connect -const t = require('../../../i18n') + +SeedImportSubview.contextTypes = { + t: PropTypes.func, +} module.exports = connect(mapStateToProps)(SeedImportSubview) + function mapStateToProps (state) { return {} } @@ -21,10 +26,10 @@ SeedImportSubview.prototype.render = function () { style: { }, }, [ - t('pasteSeed'), + this.context.t('pasteSeed'), h('textarea'), h('br'), - h('button', t('submit')), + h('button', this.context.t('submit')), ]) ) } diff --git a/ui/app/accounts/new-account/create-form.js b/ui/app/accounts/new-account/create-form.js index c820cdf6d..48c74192a 100644 --- a/ui/app/accounts/new-account/create-form.js +++ b/ui/app/accounts/new-account/create-form.js @@ -1,12 +1,11 @@ const { Component } = require('react') const PropTypes = require('prop-types') const h = require('react-hyperscript') -const { connect } = require('react-redux') +const connect = require('react-redux').connect const actions = require('../../actions') -const t = require('../../../i18n') class NewAccountCreateForm extends Component { - constructor (props) { + constructor (props, context) { super(props) const { numberOfExistingAccounts = 0 } = props @@ -14,7 +13,7 @@ class NewAccountCreateForm extends Component { this.state = { newAccountName: '', - defaultAccountName: t('newAccountNumberName', [newAccountNumber]), + defaultAccountName: context.t('newAccountNumberName', [newAccountNumber]), } } @@ -25,7 +24,7 @@ class NewAccountCreateForm extends Component { return h('div.new-account-create-form', [ h('div.new-account-create-form__input-label', {}, [ - t('accountName'), + this.context.t('accountName'), ]), h('div.new-account-create-form__input-wrapper', {}, [ @@ -41,13 +40,13 @@ class NewAccountCreateForm extends Component { h('button.btn-secondary--lg.new-account-create-form__button', { onClick: () => this.props.goHome(), }, [ - t('cancel'), + this.context.t('cancel'), ]), h('button.btn-primary--lg.new-account-create-form__button', { onClick: () => this.props.createAccount(newAccountName || defaultAccountName), }, [ - t('create'), + this.context.t('create'), ]), ]), @@ -62,6 +61,7 @@ NewAccountCreateForm.propTypes = { createAccount: PropTypes.func, goHome: PropTypes.func, numberOfExistingAccounts: PropTypes.number, + t: PropTypes.func, } const mapStateToProps = state => { @@ -97,4 +97,9 @@ const mapDispatchToProps = dispatch => { } } +NewAccountCreateForm.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(NewAccountCreateForm) + diff --git a/ui/app/accounts/new-account/index.js b/ui/app/accounts/new-account/index.js index 854568c77..207cf7760 100644 --- a/ui/app/accounts/new-account/index.js +++ b/ui/app/accounts/new-account/index.js @@ -1,9 +1,9 @@ const Component = require('react').Component const h = require('react-hyperscript') +const PropTypes = require('prop-types') const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') -const t = require('../../../i18n') const { getCurrentViewContext } = require('../../selectors') const classnames = require('classnames') @@ -37,8 +37,13 @@ function AccountDetailsModal (props) { } } +AccountDetailsModal.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(AccountDetailsModal) + AccountDetailsModal.prototype.render = function () { const { displayedForm, displayForm } = this.props @@ -46,7 +51,7 @@ AccountDetailsModal.prototype.render = function () { h('div.new-account__header', [ - h('div.new-account__title', t('newAccount')), + h('div.new-account__title', this.context.t('newAccount')), h('div.new-account__tabs', [ @@ -56,7 +61,7 @@ AccountDetailsModal.prototype.render = function () { 'new-account__tabs__unselected cursor-pointer': displayedForm !== 'CREATE', }), onClick: () => displayForm('CREATE'), - }, t('createDen')), + }, this.context.t('createDen')), h('div.new-account__tabs__tab', { className: classnames('new-account__tabs__tab', { @@ -64,7 +69,7 @@ AccountDetailsModal.prototype.render = function () { 'new-account__tabs__unselected cursor-pointer': displayedForm !== 'IMPORT', }), onClick: () => displayForm('IMPORT'), - }, t('import')), + }, this.context.t('import')), ]), diff --git a/ui/app/actions.js b/ui/app/actions.js index 4a5962610..ad4270cef 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -2,6 +2,7 @@ const abi = require('human-standard-token-abi') const getBuyEthUrl = require('../../app/scripts/lib/buy-eth-url') const { getTokenAddressFromTokenObject } = require('./util') const ethUtil = require('ethereumjs-util') +const { fetchLocale } = require('../i18n-helper') var actions = { _setBackgroundConnection: _setBackgroundConnection, @@ -23,7 +24,7 @@ var actions = { NETWORK_DROPDOWN_CLOSE: 'UI_NETWORK_DROPDOWN_CLOSE', showNetworkDropdown: showNetworkDropdown, hideNetworkDropdown: hideNetworkDropdown, - // menu state + // menu state/ getNetworkStatus: 'getNetworkStatus', // transition state TRANSITION_FORWARD: 'TRANSITION_FORWARD', @@ -254,6 +255,13 @@ var actions = { SET_USE_BLOCKIE: 'SET_USE_BLOCKIE', setUseBlockie, + // locale + SET_CURRENT_LOCALE: 'SET_CURRENT_LOCALE', + SET_LOCALE_MESSAGES: 'SET_LOCALE_MESSAGES', + setCurrentLocale, + updateCurrentLocale, + setLocaleMessages, + // // Feature Flags setFeatureFlag, updateFeatureFlags, @@ -1292,7 +1300,7 @@ function retryTransaction (txId) { function setProviderType (type) { return (dispatch) => { - log.debug(`background.setProviderType`) + log.debug(`background.setProviderType`, type) background.setProviderType(type, (err, result) => { if (err) { log.error(err) @@ -1313,13 +1321,14 @@ function updateProviderType (type) { } function setRpcTarget (newRpc) { - log.debug(`background.setRpcTarget: ${newRpc}`) return (dispatch) => { + log.debug(`background.setRpcTarget: ${newRpc}`) background.setCustomRpc(newRpc, (err, result) => { if (err) { log.error(err) return dispatch(self.displayWarning('Had a problem changing networks!')) } + dispatch(actions.setSelectedToken()) }) } } @@ -1792,6 +1801,38 @@ function setUseBlockie (val) { } } +function updateCurrentLocale (key) { + return (dispatch) => { + dispatch(actions.showLoadingIndication()) + fetchLocale(key) + .then((localeMessages) => { + log.debug(`background.setCurrentLocale`) + background.setCurrentLocale(key, (err) => { + dispatch(actions.hideLoadingIndication()) + if (err) { + return dispatch(actions.displayWarning(err.message)) + } + dispatch(actions.setCurrentLocale(key)) + dispatch(actions.setLocaleMessages(localeMessages)) + }) + }) + } +} + +function setCurrentLocale (key) { + return { + type: actions.SET_CURRENT_LOCALE, + value: key, + } +} + +function setLocaleMessages (localeMessages) { + return { + type: actions.SET_LOCALE_MESSAGES, + value: localeMessages, + } +} + function setNetworkEndpoints (networkEndpointType) { return dispatch => { log.debug('background.setNetworkEndpoints') diff --git a/ui/app/add-token.js b/ui/app/add-token.js index b4ea4a532..a73874320 100644 --- a/ui/app/add-token.js +++ b/ui/app/add-token.js @@ -2,6 +2,7 @@ const inherits = require('util').inherits const Component = require('react').Component const classnames = require('classnames') const h = require('react-hyperscript') +const PropTypes = require('prop-types') const connect = require('react-redux').connect const R = require('ramda') const Fuse = require('fuse.js') @@ -26,12 +27,16 @@ const fuse = new Fuse(contractList, { const actions = require('./actions') const ethUtil = require('ethereumjs-util') const { tokenInfoGetter } = require('./token-util') -const t = require('../i18n') const emptyAddr = '0x0000000000000000000000000000000000000000' +AddTokenScreen.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(AddTokenScreen) + function mapStateToProps (state) { const { identities, tokens } = state.metamask return { @@ -51,6 +56,7 @@ inherits(AddTokenScreen, Component) function AddTokenScreen () { this.state = { isShowingConfirmation: false, + isShowingInfoBox: true, customAddress: '', customSymbol: '', customDecimals: '', @@ -140,28 +146,31 @@ AddTokenScreen.prototype.validate = function () { if (customAddress) { const validAddress = ethUtil.isValidAddress(customAddress) if (!validAddress) { - errors.customAddress = t('invalidAddress') + errors.customAddress = this.context.t('invalidAddress') } - const validDecimals = customDecimals !== null && customDecimals >= 0 && customDecimals < 36 + const validDecimals = customDecimals !== null + && customDecimals !== '' + && customDecimals >= 0 + && customDecimals < 36 if (!validDecimals) { - errors.customDecimals = t('decimalsMustZerotoTen') + errors.customDecimals = this.context.t('decimalsMustZerotoTen') } const symbolLen = customSymbol.trim().length const validSymbol = symbolLen > 0 && symbolLen < 10 if (!validSymbol) { - errors.customSymbol = t('symbolBetweenZeroTen') + errors.customSymbol = this.context.t('symbolBetweenZeroTen') } const ownAddress = identitiesList.includes(standardAddress) if (ownAddress) { - errors.customAddress = t('personalAddressDetected') + errors.customAddress = this.context.t('personalAddressDetected') } const tokenAlreadyAdded = this.checkExistingAddresses(customAddress) if (tokenAlreadyAdded) { - errors.customAddress = t('tokenAlreadyAdded') + errors.customAddress = this.context.t('tokenAlreadyAdded') } } else if ( Object.entries(selectedTokens) @@ -169,7 +178,7 @@ AddTokenScreen.prototype.validate = function () { isEmpty && !isSelected ), true) ) { - errors.tokenSelector = t('mustSelectOne') + errors.tokenSelector = this.context.t('mustSelectOne') } return { @@ -199,7 +208,7 @@ AddTokenScreen.prototype.renderCustomForm = function () { 'add-token__add-custom-field--error': errors.customAddress, }), }, [ - h('div.add-token__add-custom-label', t('tokenAddress')), + h('div.add-token__add-custom-label', this.context.t('tokenAddress')), h('input.add-token__add-custom-input', { type: 'text', onChange: this.tokenAddressDidChange, @@ -212,7 +221,7 @@ AddTokenScreen.prototype.renderCustomForm = function () { 'add-token__add-custom-field--error': errors.customSymbol, }), }, [ - h('div.add-token__add-custom-label', t('tokenSymbol')), + h('div.add-token__add-custom-label', this.context.t('tokenSymbol')), h('input.add-token__add-custom-input', { type: 'text', onChange: this.tokenSymbolDidChange, @@ -226,7 +235,7 @@ AddTokenScreen.prototype.renderCustomForm = function () { 'add-token__add-custom-field--error': errors.customDecimals, }), }, [ - h('div.add-token__add-custom-label', t('decimal')), + h('div.add-token__add-custom-label', this.context.t('decimal')), h('input.add-token__add-custom-input', { type: 'number', onChange: this.tokenDecimalsDidChange, @@ -248,7 +257,7 @@ AddTokenScreen.prototype.renderTokenList = function () { const results = [...addressSearchResult, ...fuseSearchResult] return h('div', [ - results.length > 0 && h('div.add-token__token-icons-title', t('popularTokens')), + results.length > 0 && h('div.add-token__token-icons-title', this.context.t('popularTokens')), h('div.add-token__token-icons-container', Array(6).fill(undefined) .map((_, i) => { const { logo, symbol, name, address } = results[i] || {} @@ -302,11 +311,8 @@ AddTokenScreen.prototype.renderConfirmation = function () { return ( h('div.add-token', [ h('div.add-token__wrapper', [ - h('div.add-token__title-container.add-token__confirmation-title', [ - h('div.add-token__description', t('likeToAddTokens')), - ]), h('div.add-token__content-container.add-token__confirmation-content', [ - h('div.add-token__description.add-token__confirmation-description', t('balances')), + h('div.add-token__description.add-token__confirmation-description', this.context.t('balances')), h('div.add-token__confirmation-token-list', Object.entries(tokens) .map(([ address, token ]) => ( @@ -325,10 +331,10 @@ AddTokenScreen.prototype.renderConfirmation = function () { h('div.add-token__buttons', [ h('button.btn-secondary--lg.add-token__cancel-button', { onClick: () => this.setState({ isShowingConfirmation: false }), - }, t('back')), + }, this.context.t('back')), h('button.btn-primary--lg', { onClick: () => addTokens(tokens).then(goHome), - }, t('addTokens')), + }, this.context.t('addTokens')), ]), ]) ) @@ -339,23 +345,27 @@ AddTokenScreen.prototype.displayTab = function (selectedTab) { } AddTokenScreen.prototype.renderTabs = function () { - const { displayedTab, errors } = this.state + const { isShowingInfoBox, displayedTab, errors } = this.state return displayedTab === 'CUSTOM_TOKEN' ? this.renderCustomForm() : h('div', [ h('div.add-token__wrapper', [ h('div.add-token__content-container', [ - h('div.add-token__info-box', [ - h('div.add-token__info-box__close'), - h('div.add-token__info-box__title', t('whatsThis')), - h('div.add-token__info-box__copy', t('keepTrackTokens')), - h('div.add-token__info-box__copy--blue', t('learnMore')), + isShowingInfoBox && h('div.add-token__info-box', [ + h('div.add-token__info-box__close', { + onClick: () => this.setState({ isShowingInfoBox: false }), + }), + h('div.add-token__info-box__title', this.context.t('whatsThis')), + h('div.add-token__info-box__copy', this.context.t('keepTrackTokens')), + h('a.add-token__info-box__copy--blue', { + href: 'http://metamask.helpscoutdocs.com/article/16-managing-erc20-tokens', + }, this.context.t('learnMore')), ]), h('div.add-token__input-container', [ h('input.add-token__input', { type: 'text', - placeholder: t('searchTokens'), + placeholder: this.context.t('searchTokens'), onChange: e => this.setState({ searchQuery: e.target.value }), }), h('div.add-token__search-input-error-message', errors.tokenSelector), @@ -379,26 +389,27 @@ AddTokenScreen.prototype.render = function () { onClick: () => goHome(), }, [ h('i.fa.fa-angle-left.fa-lg'), - h('span', t('cancel')), + h('span', this.context.t('cancel')), ]), - h('div.add-token__header__title', t('addTokens')), + h('div.add-token__header__title', this.context.t('addTokens')), + isShowingConfirmation && h('div.add-token__header__subtitle', this.context.t('likeToAddTokens')), !isShowingConfirmation && h('div.add-token__header__tabs', [ h('div.add-token__header__tabs__tab', { className: classnames('add-token__header__tabs__tab', { 'add-token__header__tabs__selected': displayedTab === 'SEARCH', - 'add-token__header__tabs__unselected cursor-pointer': displayedTab !== 'SEARCH', + 'add-token__header__tabs__unselected': displayedTab !== 'SEARCH', }), onClick: () => this.displayTab('SEARCH'), - }, t('search')), + }, this.context.t('search')), h('div.add-token__header__tabs__tab', { className: classnames('add-token__header__tabs__tab', { 'add-token__header__tabs__selected': displayedTab === 'CUSTOM_TOKEN', - 'add-token__header__tabs__unselected cursor-pointer': displayedTab !== 'CUSTOM_TOKEN', + 'add-token__header__tabs__unselected': displayedTab !== 'CUSTOM_TOKEN', }), onClick: () => this.displayTab('CUSTOM_TOKEN'), - }, t('customToken')), + }, this.context.t('customToken')), ]), ]), @@ -410,10 +421,10 @@ AddTokenScreen.prototype.render = function () { !isShowingConfirmation && h('div.add-token__buttons', [ h('button.btn-secondary--lg.add-token__cancel-button', { onClick: goHome, - }, t('cancel')), + }, this.context.t('cancel')), h('button.btn-primary--lg.add-token__confirm-button', { onClick: this.onNext, - }, t('next')), + }, this.context.t('next')), ]), ]) } diff --git a/ui/app/app.js b/ui/app/app.js index d1b17ab5d..0b7a7a1e0 100644 --- a/ui/app/app.js +++ b/ui/app/app.js @@ -2,9 +2,9 @@ const inherits = require('util').inherits const Component = require('react').Component const connect = require('react-redux').connect const h = require('react-hyperscript') +const PropTypes = require('prop-types') const actions = require('./actions') const classnames = require('classnames') -const t = require('../i18n') // mascara const MascaraFirstTime = require('../../mascara/src/app/first-time').default @@ -46,8 +46,13 @@ const QrView = require('./components/qr-code') // Global Modals const Modal = require('./components/modals/index').Modal +App.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(App) + inherits(App, Component) function App () { Component.call(this) } @@ -289,13 +294,13 @@ App.prototype.renderAppBar = function () { h('img.metafox-icon', { height: 42, width: 42, - src: '/images/metamask-fox.svg', + src: './images/metamask-fox.svg', }), // metamask name h('.flex-row', [ - h('h1', t('appName')), - h('div.beta-label', t('beta')), + h('h1', this.context.t('appName')), + h('div.beta-label', this.context.t('beta')), ]), ]), @@ -557,15 +562,15 @@ App.prototype.getConnectingLabel = function () { let name if (providerName === 'mainnet') { - name = t('connectingToMainnet') + name = this.context.t('connectingToMainnet') } else if (providerName === 'ropsten') { - name = t('connectingToRopsten') + name = this.context.t('connectingToRopsten') } else if (providerName === 'kovan') { - name = t('connectingToRopsten') + name = this.context.t('connectingToRopsten') } else if (providerName === 'rinkeby') { - name = t('connectingToRinkeby') + name = this.context.t('connectingToRinkeby') } else { - name = t('connectingToUnknown') + name = this.context.t('connectingToUnknown') } return name @@ -578,15 +583,15 @@ App.prototype.getNetworkName = function () { let name if (providerName === 'mainnet') { - name = t('mainnet') + name = this.context.t('mainnet') } else if (providerName === 'ropsten') { - name = t('ropsten') + name = this.context.t('ropsten') } else if (providerName === 'kovan') { - name = t('kovan') + name = this.context.t('kovan') } else if (providerName === 'rinkeby') { - name = t('rinkeby') + name = this.context.t('rinkeby') } else { - name = t('unknownNetwork') + name = this.context.t('unknownNetwork') } return name diff --git a/ui/app/components/account-dropdowns.js b/ui/app/components/account-dropdowns.js index 1612d7b6a..03955e077 100644 --- a/ui/app/components/account-dropdowns.js +++ b/ui/app/components/account-dropdowns.js @@ -9,7 +9,6 @@ const DropdownMenuItem = require('./dropdown').DropdownMenuItem const Identicon = require('./identicon') const ethUtil = require('ethereumjs-util') const copyToClipboard = require('copy-to-clipboard') -const t = require('../../i18n') class AccountDropdowns extends Component { constructor (props) { @@ -80,7 +79,7 @@ class AccountDropdowns extends Component { try { // Sometimes keyrings aren't loaded yet: const type = keyring.type const isLoose = type !== 'HD Key Tree' - return isLoose ? h('.keyring-label.allcaps', t('loose')) : null + return isLoose ? h('.keyring-label.allcaps', this.context.t('loose')) : null } catch (e) { return } } @@ -130,7 +129,7 @@ class AccountDropdowns extends Component { diameter: 32, }, ), - h('span', { style: { marginLeft: '20px', fontSize: '24px' } }, t('createAccount')), + h('span', { style: { marginLeft: '20px', fontSize: '24px' } }, this.context.t('createAccount')), ], ), h( @@ -155,7 +154,7 @@ class AccountDropdowns extends Component { fontSize: '24px', marginBottom: '5px', }, - }, t('importAccount')), + }, this.context.t('importAccount')), ] ), ] @@ -193,7 +192,7 @@ class AccountDropdowns extends Component { global.platform.openWindow({ url }) }, }, - t('etherscanView'), + this.context.t('etherscanView'), ), h( DropdownMenuItem, @@ -205,7 +204,7 @@ class AccountDropdowns extends Component { actions.showQrView(selected, identity ? identity.name : '') }, }, - t('showQRCode'), + this.context.t('showQRCode'), ), h( DropdownMenuItem, @@ -217,7 +216,7 @@ class AccountDropdowns extends Component { copyToClipboard(checkSumAddress) }, }, - t('copyAddress'), + this.context.t('copyAddress'), ), h( DropdownMenuItem, @@ -227,7 +226,7 @@ class AccountDropdowns extends Component { actions.requestAccountExport() }, }, - t('exportPrivateKey'), + this.context.t('exportPrivateKey'), ), ] ) @@ -301,6 +300,7 @@ AccountDropdowns.propTypes = { style: PropTypes.object, enableAccountOptions: PropTypes.bool, enableAccountsSelector: PropTypes.bool, + t: PropTypes.func, } const mapDispatchToProps = (dispatch) => { @@ -316,6 +316,10 @@ const mapDispatchToProps = (dispatch) => { } } +AccountDropdowns.contextTypes = { + t: PropTypes.func, +} + module.exports = { AccountDropdowns: connect(null, mapDispatchToProps)(AccountDropdowns), } diff --git a/ui/app/components/account-export.js b/ui/app/components/account-export.js index 5637bc8d0..865207487 100644 --- a/ui/app/components/account-export.js +++ b/ui/app/components/account-export.js @@ -1,15 +1,20 @@ const Component = require('react').Component const h = require('react-hyperscript') +const PropTypes = require('prop-types') const inherits = require('util').inherits const exportAsFile = require('../util').exportAsFile const copyToClipboard = require('copy-to-clipboard') const actions = require('../actions') const ethUtil = require('ethereumjs-util') const connect = require('react-redux').connect -const t = require('../../i18n') + +ExportAccountView.contextTypes = { + t: PropTypes.func, +} module.exports = connect(mapStateToProps)(ExportAccountView) + inherits(ExportAccountView, Component) function ExportAccountView () { Component.call(this) @@ -36,7 +41,7 @@ ExportAccountView.prototype.render = function () { if (notExporting) return h('div') if (exportRequested) { - const warning = t('exportPrivateKeyWarning') + const warning = this.context.t('exportPrivateKeyWarning') return ( h('div', { style: { @@ -54,7 +59,7 @@ ExportAccountView.prototype.render = function () { h('p.error', warning), h('input#exportAccount.sizing-input', { type: 'password', - placeholder: t('confirmPassword').toLowerCase(), + placeholder: this.context.t('confirmPassword').toLowerCase(), onKeyPress: this.onExportKeyPress.bind(this), style: { position: 'relative', @@ -75,10 +80,10 @@ ExportAccountView.prototype.render = function () { style: { marginRight: '10px', }, - }, t('submit')), + }, this.context.t('submit')), h('button', { onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address)), - }, t('cancel')), + }, this.context.t('cancel')), ]), (this.props.warning) && ( h('span.error', { @@ -99,7 +104,7 @@ ExportAccountView.prototype.render = function () { margin: '0 20px', }, }, [ - h('label', t('copyPrivateKey') + ':'), + h('label', this.context.t('copyPrivateKey') + ':'), h('p.error.cursor-pointer', { style: { textOverflow: 'ellipsis', @@ -113,13 +118,13 @@ ExportAccountView.prototype.render = function () { }, plainKey), h('button', { onClick: () => this.props.dispatch(actions.backToAccountDetail(this.props.address)), - }, t('done')), + }, this.context.t('done')), h('button', { style: { marginLeft: '10px', }, onClick: () => exportAsFile(`MetaMask ${nickname} Private Key`, plainKey), - }, t('saveAsFile')), + }, this.context.t('saveAsFile')), ]) } } diff --git a/ui/app/components/account-menu/index.js b/ui/app/components/account-menu/index.js index e838e8916..21de358d6 100644 --- a/ui/app/components/account-menu/index.js +++ b/ui/app/components/account-menu/index.js @@ -1,15 +1,20 @@ const inherits = require('util').inherits const Component = require('react').Component +const PropTypes = require('prop-types') const connect = require('react-redux').connect const h = require('react-hyperscript') const actions = require('../../actions') const { Menu, Item, Divider, CloseArea } = require('../dropdowns/components/menu') const Identicon = require('../identicon') const { formatBalance } = require('../../util') -const t = require('../../../i18n') + +AccountMenu.contextTypes = { + t: PropTypes.func, +} module.exports = connect(mapStateToProps, mapDispatchToProps)(AccountMenu) + inherits(AccountMenu, Component) function AccountMenu () { Component.call(this) } @@ -71,10 +76,10 @@ AccountMenu.prototype.render = function () { h(Item, { className: 'account-menu__header', }, [ - t('myAccounts'), + this.context.t('myAccounts'), h('button.account-menu__logout-button', { onClick: lockMetamask, - }, t('logout')), + }, this.context.t('logout')), ]), h(Divider), h('div.account-menu__accounts', this.renderAccounts()), @@ -82,23 +87,23 @@ AccountMenu.prototype.render = function () { h(Item, { onClick: () => showNewAccountPage('CREATE'), icon: h('img.account-menu__item-icon', { src: 'images/plus-btn-white.svg' }), - text: t('createAccount'), + text: this.context.t('createAccount'), }), h(Item, { onClick: () => showNewAccountPage('IMPORT'), icon: h('img.account-menu__item-icon', { src: 'images/import-account.svg' }), - text: t('importAccount'), + text: this.context.t('importAccount'), }), h(Divider), h(Item, { onClick: showInfoPage, icon: h('img', { src: 'images/mm-info-icon.svg' }), - text: t('infoHelp'), + text: this.context.t('infoHelp'), }), h(Item, { onClick: showConfigPage, icon: h('img.account-menu__item-icon', { src: 'images/settings.svg' }), - text: t('settings'), + text: this.context.t('settings'), }), ]) } @@ -156,6 +161,6 @@ AccountMenu.prototype.indicateIfLoose = function (keyring) { try { // Sometimes keyrings aren't loaded yet: const type = keyring.type const isLoose = type !== 'HD Key Tree' - return isLoose ? h('.keyring-label.allcaps', t('imported')) : null + return isLoose ? h('.keyring-label.allcaps', this.context.t('imported')) : null } catch (e) { return } } diff --git a/ui/app/components/bn-as-decimal-input.js b/ui/app/components/bn-as-decimal-input.js index 70701b039..9a033f893 100644 --- a/ui/app/components/bn-as-decimal-input.js +++ b/ui/app/components/bn-as-decimal-input.js @@ -1,12 +1,18 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const ethUtil = require('ethereumjs-util') const BN = ethUtil.BN const extend = require('xtend') -const t = require('../../i18n') +const connect = require('react-redux').connect + +BnAsDecimalInput.contextTypes = { + t: PropTypes.func, +} + +module.exports = connect()(BnAsDecimalInput) -module.exports = BnAsDecimalInput inherits(BnAsDecimalInput, Component) function BnAsDecimalInput () { @@ -137,13 +143,13 @@ BnAsDecimalInput.prototype.constructWarning = function () { let message = name ? name + ' ' : '' if (min && max) { - message += t('betweenMinAndMax', [`${newMin} ${suffix}`, `${newMax} ${suffix}`]) + message += this.context.t('betweenMinAndMax', [`${newMin} ${suffix}`, `${newMax} ${suffix}`]) } else if (min) { - message += t('greaterThanMin', [`${newMin} ${suffix}`]) + message += this.context.t('greaterThanMin', [`${newMin} ${suffix}`]) } else if (max) { - message += t('lessThanMax', [`${newMax} ${suffix}`]) + message += this.context.t('lessThanMax', [`${newMax} ${suffix}`]) } else { - message += t('invalidInput') + message += this.context.t('invalidInput') } return message diff --git a/ui/app/components/buy-button-subview.js b/ui/app/components/buy-button-subview.js index 1e277a94b..9ac565cf4 100644 --- a/ui/app/components/buy-button-subview.js +++ b/ui/app/components/buy-button-subview.js @@ -1,4 +1,5 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect @@ -9,10 +10,14 @@ const Loading = require('./loading') const AccountPanel = require('./account-panel') const RadioList = require('./custom-radio-list') const networkNames = require('../../../app/scripts/config.js').networkNames -const t = require('../../i18n') + +BuyButtonSubview.contextTypes = { + t: PropTypes.func, +} module.exports = connect(mapStateToProps)(BuyButtonSubview) + function mapStateToProps (state) { return { identity: state.appState.identity, @@ -77,7 +82,7 @@ BuyButtonSubview.prototype.headerSubview = function () { paddingTop: '4px', paddingBottom: '4px', }, - }, t('depositEth')), + }, this.context.t('depositEth')), ]), // loading indication @@ -119,7 +124,7 @@ BuyButtonSubview.prototype.headerSubview = function () { paddingTop: '4px', paddingBottom: '4px', }, - }, t('selectService')), + }, this.context.t('selectService')), ]), ]) @@ -144,7 +149,7 @@ BuyButtonSubview.prototype.primarySubview = function () { case '4': case '42': const networkName = networkNames[network] - const label = `${networkName} ${t('testFaucet')}` + const label = `${networkName} ${this.context.t('testFaucet')}` return ( h('div.flex-column', { style: { @@ -165,14 +170,14 @@ BuyButtonSubview.prototype.primarySubview = function () { style: { marginTop: '15px', }, - }, t('borrowDharma')) + }, this.context.t('borrowDharma')) ) : null, ]) ) default: return ( - h('h2.error', t('unknownNetworkId')) + h('h2.error', this.context.t('unknownNetworkId')) ) } @@ -204,8 +209,8 @@ BuyButtonSubview.prototype.mainnetSubview = function () { 'ShapeShift', ], subtext: { - 'Coinbase': `${t('crypto')}/${t('fiat')} (${t('usaOnly')})`, - 'ShapeShift': t('crypto'), + 'Coinbase': `${this.context.t('crypto')}/${this.context.t('fiat')} (${this.context.t('usaOnly')})`, + 'ShapeShift': this.context.t('crypto'), }, onClick: this.radioHandler.bind(this), }), diff --git a/ui/app/components/coinbase-form.js b/ui/app/components/coinbase-form.js index e442b43d5..d5915292e 100644 --- a/ui/app/components/coinbase-form.js +++ b/ui/app/components/coinbase-form.js @@ -1,12 +1,17 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../actions') -const t = require('../../i18n') + +CoinbaseForm.contextTypes = { + t: PropTypes.func, +} module.exports = connect(mapStateToProps)(CoinbaseForm) + function mapStateToProps (state) { return { warning: state.appState.warning, @@ -38,11 +43,11 @@ CoinbaseForm.prototype.render = function () { }, [ h('button.btn-green', { onClick: this.toCoinbase.bind(this), - }, t('continueToCoinbase')), + }, this.context.t('continueToCoinbase')), h('button.btn-red', { onClick: () => props.dispatch(actions.goHome()), - }, t('cancel')), + }, this.context.t('cancel')), ]), ]) } diff --git a/ui/app/components/copyButton.js b/ui/app/components/copyButton.js index 355f78d45..a60d33523 100644 --- a/ui/app/components/copyButton.js +++ b/ui/app/components/copyButton.js @@ -1,12 +1,18 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const copyToClipboard = require('copy-to-clipboard') -const t = require('../../i18n') +const connect = require('react-redux').connect const Tooltip = require('./tooltip') -module.exports = CopyButton +CopyButton.contextTypes = { + t: PropTypes.func, +} + +module.exports = connect()(CopyButton) + inherits(CopyButton, Component) function CopyButton () { @@ -23,7 +29,7 @@ CopyButton.prototype.render = function () { const value = props.value const copied = state.copied - const message = copied ? t('copiedButton') : props.title || t('copyButton') + const message = copied ? this.context.t('copiedButton') : props.title || this.context.t('copyButton') return h('.copy-button', { style: { diff --git a/ui/app/components/copyable.js b/ui/app/components/copyable.js index fca7d3863..ad504deb8 100644 --- a/ui/app/components/copyable.js +++ b/ui/app/components/copyable.js @@ -1,12 +1,18 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const Tooltip = require('./tooltip') const copyToClipboard = require('copy-to-clipboard') -const t = require('../../i18n') +const connect = require('react-redux').connect + +Copyable.contextTypes = { + t: PropTypes.func, +} + +module.exports = connect()(Copyable) -module.exports = Copyable inherits(Copyable, Component) function Copyable () { @@ -23,7 +29,7 @@ Copyable.prototype.render = function () { const { copied } = state return h(Tooltip, { - title: copied ? t('copiedExclamation') : t('copy'), + title: copied ? this.context.t('copiedExclamation') : this.context.t('copy'), position: 'bottom', }, h('span', { style: { diff --git a/ui/app/components/customize-gas-modal/index.js b/ui/app/components/customize-gas-modal/index.js index 22ad98ce4..4c693d1c3 100644 --- a/ui/app/components/customize-gas-modal/index.js +++ b/ui/app/components/customize-gas-modal/index.js @@ -1,9 +1,9 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') -const t = require('../../../i18n') const GasModalCard = require('./gas-modal-card') const ethUtil = require('ethereumjs-util') @@ -65,6 +65,7 @@ function mapDispatchToProps (dispatch) { updateGasLimit: newGasLimit => dispatch(actions.updateGasLimit(newGasLimit)), updateGasTotal: newGasTotal => dispatch(actions.updateGasTotal(newGasTotal)), updateSendAmount: newAmount => dispatch(actions.updateSendAmount(newAmount)), + updateSendErrors: error => dispatch(actions.updateSendErrors(error)), } } @@ -95,8 +96,13 @@ function CustomizeGasModal (props) { this.state = getOriginalState(props) } +CustomizeGasModal.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(CustomizeGasModal) + CustomizeGasModal.prototype.save = function (gasPrice, gasLimit, gasTotal) { const { updateGasPrice, @@ -107,6 +113,7 @@ CustomizeGasModal.prototype.save = function (gasPrice, gasLimit, gasTotal) { selectedToken, balance, updateSendAmount, + updateSendErrors, } = this.props if (maxModeOn && !selectedToken) { @@ -121,6 +128,7 @@ CustomizeGasModal.prototype.save = function (gasPrice, gasLimit, gasTotal) { updateGasPrice(ethUtil.addHexPrefix(gasPrice)) updateGasLimit(ethUtil.addHexPrefix(gasLimit)) updateGasTotal(ethUtil.addHexPrefix(gasTotal)) + updateSendErrors({ insufficientFunds: false }) hideModal() } @@ -150,7 +158,7 @@ CustomizeGasModal.prototype.validate = function ({ gasTotal, gasLimit }) { }) if (!balanceIsSufficient) { - error = t('balanceIsInsufficientGas') + error = this.context.t('balanceIsInsufficientGas') } const gasLimitTooLow = gasLimit && conversionGreaterThan( @@ -166,7 +174,7 @@ CustomizeGasModal.prototype.validate = function ({ gasTotal, gasLimit }) { ) if (gasLimitTooLow) { - error = t('gasLimitTooLow') + error = this.context.t('gasLimitTooLow') } this.setState({ error }) @@ -259,7 +267,7 @@ CustomizeGasModal.prototype.render = function () { }, [ h('div.send-v2__customize-gas__header', {}, [ - h('div.send-v2__customize-gas__title', t('customGas')), + h('div.send-v2__customize-gas__title', this.context.t('customGas')), h('div.send-v2__customize-gas__close', { onClick: hideModal, @@ -275,8 +283,8 @@ CustomizeGasModal.prototype.render = function () { // max: 1000, step: multiplyCurrencies(MIN_GAS_PRICE_GWEI, 10), onChange: value => this.convertAndSetGasPrice(value), - title: t('gasPrice'), - copy: t('gasPriceCalculation'), + title: this.context.t('gasPrice'), + copy: this.context.t('gasPriceCalculation'), }), h(GasModalCard, { @@ -285,8 +293,8 @@ CustomizeGasModal.prototype.render = function () { // max: 100000, step: 1, onChange: value => this.convertAndSetGasLimit(value), - title: t('gasLimit'), - copy: t('gasLimitCalculation'), + title: this.context.t('gasLimit'), + copy: this.context.t('gasLimitCalculation'), }), ]), @@ -299,7 +307,7 @@ CustomizeGasModal.prototype.render = function () { h('div.send-v2__customize-gas__revert', { onClick: () => this.revert(), - }, [t('revert')]), + }, [this.context.t('revert')]), h('div.send-v2__customize-gas__buttons', [ h('button.btn-secondary.send-v2__customize-gas__cancel', { @@ -307,12 +315,12 @@ CustomizeGasModal.prototype.render = function () { style: { marginRight: '10px', }, - }, [t('cancel')]), + }, [this.context.t('cancel')]), h('button.btn-primary.send-v2__customize-gas__save', { onClick: () => !error && this.save(newGasPrice, gasLimit, gasTotal), className: error && 'btn-primary--disabled', - }, [t('save')]), + }, [this.context.t('save')]), ]), ]), diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js index e5359c1d6..a133f0e29 100644 --- a/ui/app/components/dropdowns/components/account-dropdowns.js +++ b/ui/app/components/dropdowns/components/account-dropdowns.js @@ -10,7 +10,7 @@ const Identicon = require('../../identicon') const ethUtil = require('ethereumjs-util') const copyToClipboard = require('copy-to-clipboard') const { formatBalance } = require('../../../util') -const t = require('../../../../i18n') + class AccountDropdowns extends Component { constructor (props) { @@ -130,7 +130,7 @@ class AccountDropdowns extends Component { actions.showEditAccountModal(identity) }, }, [ - t('edit'), + this.context.t('edit'), ]), ]), @@ -144,7 +144,7 @@ class AccountDropdowns extends Component { try { // Sometimes keyrings aren't loaded yet: const type = keyring.type const isLoose = type !== 'HD Key Tree' - return isLoose ? h('.keyring-label.allcaps', t('loose')) : null + return isLoose ? h('.keyring-label.allcaps', this.context.t('loose')) : null } catch (e) { return } } @@ -202,7 +202,7 @@ class AccountDropdowns extends Component { fontSize: '16px', lineHeight: '23px', }, - }, t('createAccount')), + }, this.context.t('createAccount')), ], ), h( @@ -236,7 +236,7 @@ class AccountDropdowns extends Component { fontSize: '16px', lineHeight: '23px', }, - }, t('importAccount')), + }, this.context.t('importAccount')), ] ), ] @@ -287,7 +287,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - t('accountDetails'), + this.context.t('accountDetails'), ), h( DropdownMenuItem, @@ -303,7 +303,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - t('etherscanView'), + this.context.t('etherscanView'), ), h( DropdownMenuItem, @@ -319,7 +319,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - t('copyAddress'), + this.context.t('copyAddress'), ), h( DropdownMenuItem, @@ -331,7 +331,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - t('exportPrivateKey'), + this.context.t('exportPrivateKey'), ), h( DropdownMenuItem, @@ -346,7 +346,7 @@ class AccountDropdowns extends Component { menuItemStyles, ), }, - t('addToken'), + this.context.t('addToken'), ), ] @@ -425,6 +425,7 @@ AccountDropdowns.propTypes = { enableAccountsSelector: PropTypes.bool, enableAccountOption: PropTypes.bool, enableAccountOptions: PropTypes.bool, + t: PropTypes.func, } const mapDispatchToProps = (dispatch) => { @@ -463,4 +464,9 @@ function mapStateToProps (state) { } } +AccountDropdowns.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(AccountDropdowns) + diff --git a/ui/app/components/dropdowns/network-dropdown.js b/ui/app/components/dropdowns/network-dropdown.js index 5afe730c1..9e47f38ef 100644 --- a/ui/app/components/dropdowns/network-dropdown.js +++ b/ui/app/components/dropdowns/network-dropdown.js @@ -1,4 +1,5 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect @@ -6,9 +7,9 @@ const actions = require('../../actions') const Dropdown = require('./components/dropdown').Dropdown const DropdownMenuItem = require('./components/dropdown').DropdownMenuItem const NetworkDropdownIcon = require('./components/network-dropdown-icon') -const t = require('../../../i18n') const R = require('ramda') + // classes from nodes of the toggle element. const notToggleElementClassnames = [ 'menu-icon', @@ -54,8 +55,13 @@ function NetworkDropdown () { Component.call(this) } +NetworkDropdown.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(NetworkDropdown) + // TODO: specify default props and proptypes NetworkDropdown.prototype.render = function () { const props = this.props @@ -94,13 +100,13 @@ NetworkDropdown.prototype.render = function () { }, [ h('div.network-dropdown-header', {}, [ - h('div.network-dropdown-title', {}, t('networks')), + h('div.network-dropdown-title', {}, this.context.t('networks')), h('div.network-dropdown-divider'), h('div.network-dropdown-content', {}, - t('defaultNetwork') + this.context.t('defaultNetwork') ), ]), @@ -122,7 +128,7 @@ NetworkDropdown.prototype.render = function () { style: { color: providerType === 'mainnet' ? '#ffffff' : '#9b9b9b', }, - }, t('mainnet')), + }, this.context.t('mainnet')), ] ), @@ -144,7 +150,7 @@ NetworkDropdown.prototype.render = function () { style: { color: providerType === 'ropsten' ? '#ffffff' : '#9b9b9b', }, - }, t('ropsten')), + }, this.context.t('ropsten')), ] ), @@ -166,7 +172,7 @@ NetworkDropdown.prototype.render = function () { style: { color: providerType === 'kovan' ? '#ffffff' : '#9b9b9b', }, - }, t('kovan')), + }, this.context.t('kovan')), ] ), @@ -188,7 +194,7 @@ NetworkDropdown.prototype.render = function () { style: { color: providerType === 'rinkeby' ? '#ffffff' : '#9b9b9b', }, - }, t('rinkeby')), + }, this.context.t('rinkeby')), ] ), @@ -197,20 +203,20 @@ NetworkDropdown.prototype.render = function () { { key: 'default', closeMenu: () => this.props.hideNetworkDropdown(), - onClick: () => props.setRpcTarget('http://localhost:8545'), + onClick: () => props.setProviderType('localhost'), style: dropdownMenuItemStyle, }, [ - activeNetwork === 'http://localhost:8545' ? h('i.fa.fa-check') : h('.network-check__transparent', '✓'), + providerType === 'localhost' ? h('i.fa.fa-check') : h('.network-check__transparent', '✓'), h(NetworkDropdownIcon, { - isSelected: activeNetwork === 'http://localhost:8545', + isSelected: providerType === 'localhost', innerBorder: '1px solid #9b9b9b', }), h('span.network-name-item', { style: { - color: activeNetwork === 'http://localhost:8545' ? '#ffffff' : '#9b9b9b', + color: providerType === 'localhost' ? '#ffffff' : '#9b9b9b', }, - }, t('localhost')), + }, this.context.t('localhost')), ] ), @@ -234,7 +240,7 @@ NetworkDropdown.prototype.render = function () { style: { color: activeNetwork === 'custom' ? '#ffffff' : '#9b9b9b', }, - }, t('customRPC')), + }, this.context.t('customRPC')), ] ), @@ -249,15 +255,15 @@ NetworkDropdown.prototype.getNetworkName = function () { let name if (providerName === 'mainnet') { - name = t('mainnet') + name = this.context.t('mainnet') } else if (providerName === 'ropsten') { - name = t('ropsten') + name = this.context.t('ropsten') } else if (providerName === 'kovan') { - name = t('kovan') + name = this.context.t('kovan') } else if (providerName === 'rinkeby') { - name = t('rinkeby') + name = this.context.t('rinkeby') } else { - name = t('unknownNetwork') + name = this.context.t('unknownNetwork') } return name diff --git a/ui/app/components/dropdowns/token-menu-dropdown.js b/ui/app/components/dropdowns/token-menu-dropdown.js index a4f93b505..b70d0b893 100644 --- a/ui/app/components/dropdowns/token-menu-dropdown.js +++ b/ui/app/components/dropdowns/token-menu-dropdown.js @@ -1,12 +1,18 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') -const t = require('../../../i18n') + + +TokenMenuDropdown.contextTypes = { + t: PropTypes.func, +} module.exports = connect(null, mapDispatchToProps)(TokenMenuDropdown) + function mapDispatchToProps (dispatch) { return { showHideTokenConfirmationModal: (token) => { @@ -44,7 +50,7 @@ TokenMenuDropdown.prototype.render = function () { showHideTokenConfirmationModal(this.props.token) this.props.onClose() }, - }, t('hideToken')), + }, this.context.t('hideToken')), ]), ]), diff --git a/ui/app/components/ens-input.js b/ui/app/components/ens-input.js index 1b2d4009d..1f3946817 100644 --- a/ui/app/components/ens-input.js +++ b/ui/app/components/ens-input.js @@ -1,4 +1,5 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const extend = require('xtend') @@ -8,11 +9,15 @@ const ENS = require('ethjs-ens') const networkMap = require('ethjs-ens/lib/network-map.json') const ensRE = /.+\..+$/ const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' -const t = require('../../i18n') +const connect = require('react-redux').connect const ToAutoComplete = require('./send/to-autocomplete') +EnsInput.contextTypes = { + t: PropTypes.func, +} + +module.exports = connect()(EnsInput) -module.exports = EnsInput inherits(EnsInput, Component) function EnsInput () { @@ -71,13 +76,13 @@ EnsInput.prototype.lookupEnsName = function (recipient) { log.info(`ENS attempting to resolve name: ${recipient}`) this.ens.lookup(recipient.trim()) .then((address) => { - if (address === ZERO_ADDRESS) throw new Error(t('noAddressForName')) + if (address === ZERO_ADDRESS) throw new Error(this.context.t('noAddressForName')) if (address !== ensResolution) { this.setState({ loadingEns: false, ensResolution: address, nickname: recipient.trim(), - hoverText: address + '\n' + t('clickCopy'), + hoverText: address + '\n' + this.context.t('clickCopy'), ensFailure: false, }) } diff --git a/ui/app/components/hex-as-decimal-input.js b/ui/app/components/hex-as-decimal-input.js index a43d44f89..75303a34a 100644 --- a/ui/app/components/hex-as-decimal-input.js +++ b/ui/app/components/hex-as-decimal-input.js @@ -1,12 +1,18 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const ethUtil = require('ethereumjs-util') const BN = ethUtil.BN const extend = require('xtend') -const t = require('../../i18n') +const connect = require('react-redux').connect + +HexAsDecimalInput.contextTypes = { + t: PropTypes.func, +} + +module.exports = connect()(HexAsDecimalInput) -module.exports = HexAsDecimalInput inherits(HexAsDecimalInput, Component) function HexAsDecimalInput () { @@ -127,13 +133,13 @@ HexAsDecimalInput.prototype.constructWarning = function () { let message = name ? name + ' ' : '' if (min && max) { - message += t('betweenMinAndMax', [min, max]) + message += this.context.t('betweenMinAndMax', [min, max]) } else if (min) { - message += t('greaterThanMin', [min]) + message += this.context.t('greaterThanMin', [min]) } else if (max) { - message += t('lessThanMax', [max]) + message += this.context.t('lessThanMax', [max]) } else { - message += t('invalidInput') + message += this.context.t('invalidInput') } return message diff --git a/ui/app/components/identicon.js b/ui/app/components/identicon.js index b803b7ceb..dce9b0449 100644 --- a/ui/app/components/identicon.js +++ b/ui/app/components/identicon.js @@ -47,7 +47,7 @@ IdenticonComponent.prototype.render = function () { ) : ( h('img.balance-icon', { - src: '../images/eth_logo.svg', + src: './images/eth_logo.svg', style: { height: diameter, width: diameter, @@ -105,9 +105,8 @@ IdenticonComponent.prototype.componentDidUpdate = function () { function _generateBlockie (container, address, diameter) { const img = new Image() img.src = toDataUrl(address) - const dia = !diameter || diameter < 50 ? 50 : diameter - img.height = dia * 1.25 - img.width = dia * 1.25 + img.height = diameter + img.width = diameter container.appendChild(img) } diff --git a/ui/app/components/modals/account-details-modal.js b/ui/app/components/modals/account-details-modal.js index 927d73482..d9885daf5 100644 --- a/ui/app/components/modals/account-details-modal.js +++ b/ui/app/components/modals/account-details-modal.js @@ -1,4 +1,5 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect @@ -8,7 +9,6 @@ const { getSelectedIdentity } = require('../../selectors') const genAccountLink = require('../../../lib/account-link.js') const QrView = require('../qr-code') const EditableLabel = require('../editable-label') -const t = require('../../../i18n') function mapStateToProps (state) { return { @@ -34,8 +34,13 @@ function AccountDetailsModal () { Component.call(this) } +AccountDetailsModal.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(AccountDetailsModal) + // Not yet pixel perfect todos: // fonts of qr-header @@ -65,12 +70,12 @@ AccountDetailsModal.prototype.render = function () { h('button.btn-primary.account-modal__button', { onClick: () => global.platform.openWindow({ url: genAccountLink(address, network) }), - }, t('etherscanView')), + }, this.context.t('etherscanView')), // Holding on redesign for Export Private Key functionality h('button.btn-primary.account-modal__button', { onClick: () => showExportPrivateKeyModal(), - }, t('exportPrivateKey')), + }, this.context.t('exportPrivateKey')), ]) } diff --git a/ui/app/components/modals/account-modal-container.js b/ui/app/components/modals/account-modal-container.js index 08540aa76..a9856b20f 100644 --- a/ui/app/components/modals/account-modal-container.js +++ b/ui/app/components/modals/account-modal-container.js @@ -1,11 +1,11 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') const { getSelectedIdentity } = require('../../selectors') const Identicon = require('../identicon') -const t = require('../../../i18n') function mapStateToProps (state) { return { @@ -26,8 +26,13 @@ function AccountModalContainer () { Component.call(this) } +AccountModalContainer.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(AccountModalContainer) + AccountModalContainer.prototype.render = function () { const { selectedIdentity, @@ -60,7 +65,7 @@ AccountModalContainer.prototype.render = function () { h('i.fa.fa-angle-left.fa-lg'), - h('span.account-modal-back__text', ' ' + t('back')), + h('span.account-modal-back__text', ' ' + this.context.t('back')), ]), diff --git a/ui/app/components/modals/buy-options-modal.js b/ui/app/components/modals/buy-options-modal.js index 7eb73c3a6..d871e7516 100644 --- a/ui/app/components/modals/buy-options-modal.js +++ b/ui/app/components/modals/buy-options-modal.js @@ -1,10 +1,10 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') const networkNames = require('../../../../app/scripts/config.js').networkNames -const t = require('../../../i18n') function mapStateToProps (state) { return { @@ -33,8 +33,13 @@ function BuyOptions () { Component.call(this) } +BuyOptions.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(BuyOptions) + BuyOptions.prototype.renderModalContentOption = function (title, header, onClick) { return h('div.buy-modal-content-option', { onClick, @@ -57,15 +62,15 @@ BuyOptions.prototype.render = function () { }, [ h('div.buy-modal-content-title', { style: {}, - }, t('transfers')), - h('div', {}, t('howToDeposit')), + }, this.context.t('transfers')), + h('div', {}, this.context.t('howToDeposit')), ]), h('div.buy-modal-content-options.flex-column.flex-center', {}, [ isTestNetwork - ? this.renderModalContentOption(networkName, t('testFaucet'), () => toFaucet(network)) - : this.renderModalContentOption('Coinbase', t('depositFiat'), () => toCoinbase(address)), + ? this.renderModalContentOption(networkName, this.context.t('testFaucet'), () => toFaucet(network)) + : this.renderModalContentOption('Coinbase', this.context.t('depositFiat'), () => toCoinbase(address)), // h('div.buy-modal-content-option', {}, [ // h('div.buy-modal-content-option-title', {}, 'Shapeshift'), @@ -73,8 +78,8 @@ BuyOptions.prototype.render = function () { // ]),, this.renderModalContentOption( - t('directDeposit'), - t('depositFromAccount'), + this.context.t('directDeposit'), + this.context.t('depositFromAccount'), () => this.goToAccountDetailsModal() ), @@ -85,7 +90,7 @@ BuyOptions.prototype.render = function () { background: 'white', }, onClick: () => { this.props.hideModal() }, - }, h('div.buy-modal-content-footer#buy-modal-content-footer-text', {}, t('cancel'))), + }, h('div.buy-modal-content-footer#buy-modal-content-footer-text', {}, this.context.t('cancel'))), ]), ]) } diff --git a/ui/app/components/modals/deposit-ether-modal.js b/ui/app/components/modals/deposit-ether-modal.js index 2de1240fc..0dc611f50 100644 --- a/ui/app/components/modals/deposit-ether-modal.js +++ b/ui/app/components/modals/deposit-ether-modal.js @@ -1,22 +1,19 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') const networkNames = require('../../../../app/scripts/config.js').networkNames const ShapeshiftForm = require('../shapeshift-form') -const t = require('../../../i18n') - -const DIRECT_DEPOSIT_ROW_TITLE = t('directDepositEther') -const DIRECT_DEPOSIT_ROW_TEXT = t('directDepositEtherExplainer') -const COINBASE_ROW_TITLE = t('buyCoinbase') -const COINBASE_ROW_TEXT = t('buyCoinbaseExplainer') -const SHAPESHIFT_ROW_TITLE = t('depositShapeShift') -const SHAPESHIFT_ROW_TEXT = t('depositShapeShiftExplainer') -const FAUCET_ROW_TITLE = t('testFaucet') -const facuetRowText = (networkName) => { - return t('getEtherFromFaucet', [networkName]) -} + +let DIRECT_DEPOSIT_ROW_TITLE +let DIRECT_DEPOSIT_ROW_TEXT +let COINBASE_ROW_TITLE +let COINBASE_ROW_TEXT +let SHAPESHIFT_ROW_TITLE +let SHAPESHIFT_ROW_TEXT +let FAUCET_ROW_TITLE function mapStateToProps (state) { return { @@ -44,16 +41,34 @@ function mapDispatchToProps (dispatch) { } inherits(DepositEtherModal, Component) -function DepositEtherModal () { +function DepositEtherModal (props, context) { Component.call(this) + // need to set after i18n locale has loaded + DIRECT_DEPOSIT_ROW_TITLE = context.t('directDepositEther') + DIRECT_DEPOSIT_ROW_TEXT = context.t('directDepositEtherExplainer') + COINBASE_ROW_TITLE = context.t('buyCoinbase') + COINBASE_ROW_TEXT = context.t('buyCoinbaseExplainer') + SHAPESHIFT_ROW_TITLE = context.t('depositShapeShift') + SHAPESHIFT_ROW_TEXT = context.t('depositShapeShiftExplainer') + FAUCET_ROW_TITLE = context.t('testFaucet') + this.state = { buyingWithShapeshift: false, } } +DepositEtherModal.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(DepositEtherModal) + +DepositEtherModal.prototype.facuetRowText = function (networkName) { + return this.context.t('getEtherFromFaucet', [networkName]) +} + DepositEtherModal.prototype.renderRow = function ({ logo, title, @@ -113,10 +128,10 @@ DepositEtherModal.prototype.render = function () { h('div.page-container__header', [ - h('div.page-container__title', [t('depositEther')]), + h('div.page-container__title', [this.context.t('depositEther')]), h('div.page-container__subtitle', [ - t('needEtherInWallet'), + this.context.t('needEtherInWallet'), ]), h('div.page-container__header-close', { @@ -135,11 +150,11 @@ DepositEtherModal.prototype.render = function () { this.renderRow({ logo: h('img.deposit-ether-modal__logo', { - src: '../../../images/deposit-eth.svg', + src: './images/deposit-eth.svg', }), title: DIRECT_DEPOSIT_ROW_TITLE, text: DIRECT_DEPOSIT_ROW_TEXT, - buttonLabel: t('viewAccount'), + buttonLabel: this.context.t('viewAccount'), onButtonClick: () => this.goToAccountDetailsModal(), hide: buyingWithShapeshift, }), @@ -147,8 +162,8 @@ DepositEtherModal.prototype.render = function () { this.renderRow({ logo: h('i.fa.fa-tint.fa-2x'), title: FAUCET_ROW_TITLE, - text: facuetRowText(networkName), - buttonLabel: t('getEther'), + text: this.facuetRowText(networkName), + buttonLabel: this.context.t('getEther'), onButtonClick: () => toFaucet(network), hide: !isTestNetwork || buyingWithShapeshift, }), @@ -156,13 +171,13 @@ DepositEtherModal.prototype.render = function () { this.renderRow({ logo: h('div.deposit-ether-modal__logo', { style: { - backgroundImage: 'url(\'../../../images/coinbase logo.png\')', + backgroundImage: 'url(\'./images/coinbase logo.png\')', height: '40px', }, }), title: COINBASE_ROW_TITLE, text: COINBASE_ROW_TEXT, - buttonLabel: t('continueToCoinbase'), + buttonLabel: this.context.t('continueToCoinbase'), onButtonClick: () => toCoinbase(address), hide: isTestNetwork || buyingWithShapeshift, }), @@ -170,12 +185,12 @@ DepositEtherModal.prototype.render = function () { this.renderRow({ logo: h('div.deposit-ether-modal__logo', { style: { - backgroundImage: 'url(\'../../../images/shapeshift logo.png\')', + backgroundImage: 'url(\'./images/shapeshift logo.png\')', }, }), title: SHAPESHIFT_ROW_TITLE, text: SHAPESHIFT_ROW_TEXT, - buttonLabel: t('shapeshiftBuy'), + buttonLabel: this.context.t('shapeshiftBuy'), onButtonClick: () => this.setState({ buyingWithShapeshift: true }), hide: isTestNetwork, hideButton: buyingWithShapeshift, diff --git a/ui/app/components/modals/edit-account-name-modal.js b/ui/app/components/modals/edit-account-name-modal.js index 6efa8d476..c79645dbf 100644 --- a/ui/app/components/modals/edit-account-name-modal.js +++ b/ui/app/components/modals/edit-account-name-modal.js @@ -1,10 +1,10 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') const { getSelectedAccount } = require('../../selectors') -const t = require('../../../i18n') function mapStateToProps (state) { return { @@ -33,8 +33,13 @@ function EditAccountNameModal (props) { } } +EditAccountNameModal.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(EditAccountNameModal) + EditAccountNameModal.prototype.render = function () { const { hideModal, saveAccountLabel, identity } = this.props @@ -51,7 +56,7 @@ EditAccountNameModal.prototype.render = function () { ]), h('div.edit-account-name-modal-title', { - }, [t('editAccountName')]), + }, [this.context.t('editAccountName')]), h('input.edit-account-name-modal-input', { placeholder: identity.name, @@ -70,7 +75,7 @@ EditAccountNameModal.prototype.render = function () { }, disabled: this.state.inputText.length === 0, }, [ - t('save'), + this.context.t('save'), ]), ]), diff --git a/ui/app/components/modals/export-private-key-modal.js b/ui/app/components/modals/export-private-key-modal.js index cf42e4fa2..1f80aed39 100644 --- a/ui/app/components/modals/export-private-key-modal.js +++ b/ui/app/components/modals/export-private-key-modal.js @@ -1,4 +1,5 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect @@ -7,7 +8,6 @@ const actions = require('../../actions') const AccountModalContainer = require('./account-modal-container') const { getSelectedIdentity } = require('../../selectors') const ReadOnlyInput = require('../readonly-input') -const t = require('../../../i18n') const copyToClipboard = require('copy-to-clipboard') function mapStateToProps (state) { @@ -38,8 +38,13 @@ function ExportPrivateKeyModal () { } } +ExportPrivateKeyModal.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(ExportPrivateKeyModal) + ExportPrivateKeyModal.prototype.exportAccountAndGetPrivateKey = function (password, address) { const { exportAccount } = this.props @@ -49,8 +54,8 @@ ExportPrivateKeyModal.prototype.exportAccountAndGetPrivateKey = function (passwo ExportPrivateKeyModal.prototype.renderPasswordLabel = function (privateKey) { return h('span.private-key-password-label', privateKey - ? t('copyPrivateKey') - : t('typePassword') + ? this.context.t('copyPrivateKey') + : this.context.t('typePassword') ) } @@ -87,8 +92,8 @@ ExportPrivateKeyModal.prototype.renderButtons = function (privateKey, password, ), (privateKey - ? this.renderButton('btn-primary--lg export-private-key__button', () => hideModal(), t('done')) - : this.renderButton('btn-primary--lg export-private-key__button', () => this.exportAccountAndGetPrivateKey(this.state.password, address), t('confirm')) + ? this.renderButton('btn-primary--lg export-private-key__button', () => hideModal(), this.context.t('done')) + : this.renderButton('btn-primary--lg export-private-key__button', () => this.exportAccountAndGetPrivateKey(this.state.password, address), this.context.t('confirm')) ), ]) @@ -121,7 +126,7 @@ ExportPrivateKeyModal.prototype.render = function () { h('div.account-modal-divider'), - h('span.modal-body-title', t('showPrivateKeys')), + h('span.modal-body-title', this.context.t('showPrivateKeys')), h('div.private-key-password', {}, [ this.renderPasswordLabel(privateKey), @@ -131,7 +136,7 @@ ExportPrivateKeyModal.prototype.render = function () { !warning ? null : h('span.private-key-password-error', warning), ]), - h('div.private-key-password-warning', t('privateKeyWarning')), + h('div.private-key-password-warning', this.context.t('privateKeyWarning')), this.renderButtons(privateKey, this.state.password, address, hideModal), diff --git a/ui/app/components/modals/hide-token-confirmation-modal.js b/ui/app/components/modals/hide-token-confirmation-modal.js index 33d8062c6..72e9c84eb 100644 --- a/ui/app/components/modals/hide-token-confirmation-modal.js +++ b/ui/app/components/modals/hide-token-confirmation-modal.js @@ -1,10 +1,10 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const connect = require('react-redux').connect const actions = require('../../actions') const Identicon = require('../identicon') -const t = require('../../../i18n') function mapStateToProps (state) { return { @@ -32,8 +32,13 @@ function HideTokenConfirmationModal () { this.state = {} } +HideTokenConfirmationModal.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(HideTokenConfirmationModal) + HideTokenConfirmationModal.prototype.render = function () { const { token, network, hideToken, hideModal } = this.props const { symbol, address } = token @@ -42,7 +47,7 @@ HideTokenConfirmationModal.prototype.render = function () { h('div.hide-token-confirmation__container', { }, [ h('div.hide-token-confirmation__title', {}, [ - t('hideTokenPrompt'), + this.context.t('hideTokenPrompt'), ]), h(Identicon, { @@ -55,19 +60,19 @@ HideTokenConfirmationModal.prototype.render = function () { h('div.hide-token-confirmation__symbol', {}, symbol), h('div.hide-token-confirmation__copy', {}, [ - t('readdToken'), + this.context.t('readdToken'), ]), h('div.hide-token-confirmation__buttons', {}, [ h('button.btn-cancel.hide-token-confirmation__button.allcaps', { onClick: () => hideModal(), }, [ - t('cancel'), + this.context.t('cancel'), ]), h('button.btn-clear.hide-token-confirmation__button.allcaps', { onClick: () => hideToken(address), }, [ - t('hide'), + this.context.t('hide'), ]), ]), ]), diff --git a/ui/app/components/modals/modal.js b/ui/app/components/modals/modal.js index 501b83430..9250cc77e 100644 --- a/ui/app/components/modals/modal.js +++ b/ui/app/components/modals/modal.js @@ -6,7 +6,6 @@ const FadeModal = require('boron').FadeModal const actions = require('../../actions') const isMobileView = require('../../../lib/is-mobile-view') const isPopupOrNotification = require('../../../../app/scripts/lib/is-popup-or-notification') -const t = require('../../../i18n') // Modal Components const BuyOptions = require('./buy-options-modal') @@ -174,8 +173,8 @@ const MODALS = { BETA_UI_NOTIFICATION_MODAL: { contents: [ h(NotifcationModal, { - header: t('uiWelcome'), - message: t('uiWelcomeMessage'), + header: 'uiWelcome', + message: 'uiWelcomeMessage', }), ], mobileModalStyle: { @@ -191,8 +190,8 @@ const MODALS = { OLD_UI_NOTIFICATION_MODAL: { contents: [ h(NotifcationModal, { - header: t('oldUI'), - message: t('oldUIMessage'), + header: 'oldUI', + message: 'oldUIMessage', }), ], mobileModalStyle: { diff --git a/ui/app/components/modals/new-account-modal.js b/ui/app/components/modals/new-account-modal.js index 298b76af4..0635b3f72 100644 --- a/ui/app/components/modals/new-account-modal.js +++ b/ui/app/components/modals/new-account-modal.js @@ -1,9 +1,8 @@ const { Component } = require('react') const PropTypes = require('prop-types') const h = require('react-hyperscript') -const { connect } = require('react-redux') +const connect = require('react-redux').connect const actions = require('../../actions') -const t = require('../../../i18n') class NewAccountModal extends Component { constructor (props) { @@ -12,7 +11,7 @@ class NewAccountModal extends Component { const newAccountNumber = numberOfExistingAccounts + 1 this.state = { - newAccountName: `${t('account')} ${newAccountNumber}`, + newAccountName: `${this.context.t('account')} ${newAccountNumber}`, } } @@ -23,7 +22,7 @@ class NewAccountModal extends Component { h('div.new-account-modal-wrapper', { }, [ h('div.new-account-modal-header', {}, [ - t('newAccount'), + this.context.t('newAccount'), ]), h('div.modal-close-x', { @@ -31,19 +30,19 @@ class NewAccountModal extends Component { }), h('div.new-account-modal-content', {}, [ - t('accountName'), + this.context.t('accountName'), ]), h('div.new-account-input-wrapper', {}, [ h('input.new-account-input', { value: this.state.newAccountName, - placeholder: t('sampleAccountName'), + placeholder: this.context.t('sampleAccountName'), onChange: event => this.setState({ newAccountName: event.target.value }), }, []), ]), h('div.new-account-modal-content.after-input', {}, [ - t('or'), + this.context.t('or'), ]), h('div.new-account-modal-content.after-input.pointer', { @@ -51,13 +50,13 @@ class NewAccountModal extends Component { this.props.hideModal() this.props.showImportPage() }, - }, t('importAnAccount')), + }, this.context.t('importAnAccount')), h('div.new-account-modal-content.button.allcaps', {}, [ h('button.btn-clear', { onClick: () => this.props.createAccount(newAccountName), }, [ - t('save'), + this.context.t('save'), ]), ]), ]), @@ -70,6 +69,7 @@ NewAccountModal.propTypes = { showImportPage: PropTypes.func, createAccount: PropTypes.func, numberOfExistingAccounts: PropTypes.number, + t: PropTypes.func, } const mapStateToProps = state => { @@ -104,4 +104,9 @@ const mapDispatchToProps = dispatch => { } } +NewAccountModal.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(NewAccountModal) + diff --git a/ui/app/components/modals/notification-modal.js b/ui/app/components/modals/notification-modal.js index 621a974d0..46a4c8a21 100644 --- a/ui/app/components/modals/notification-modal.js +++ b/ui/app/components/modals/notification-modal.js @@ -1,7 +1,7 @@ const { Component } = require('react') const PropTypes = require('prop-types') const h = require('react-hyperscript') -const { connect } = require('react-redux') +const connect = require('react-redux').connect const actions = require('../../actions') class NotificationModal extends Component { @@ -22,12 +22,12 @@ class NotificationModal extends Component { }, [ h('div.notification-modal__header', {}, [ - header, + this.context.t(header), ]), h('div.notification-modal__message-wrapper', {}, [ h('div.notification-modal__message', {}, [ - message, + this.context.t(message), ]), ]), @@ -62,6 +62,7 @@ NotificationModal.propTypes = { showCancelButton: PropTypes.bool, showConfirmButton: PropTypes.bool, onConfirm: PropTypes.func, + t: PropTypes.func, } const mapDispatchToProps = dispatch => { @@ -72,4 +73,9 @@ const mapDispatchToProps = dispatch => { } } +NotificationModal.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(null, mapDispatchToProps)(NotificationModal) + diff --git a/ui/app/components/modals/notification-modals/confirm-reset-account.js b/ui/app/components/modals/notification-modals/confirm-reset-account.js index e1bc91b24..89fa9bef1 100644 --- a/ui/app/components/modals/notification-modals/confirm-reset-account.js +++ b/ui/app/components/modals/notification-modals/confirm-reset-account.js @@ -1,7 +1,7 @@ const { Component } = require('react') const PropTypes = require('prop-types') const h = require('react-hyperscript') -const { connect } = require('react-redux') +const connect = require('react-redux').connect const actions = require('../../../actions') const NotifcationModal = require('../notification-modal') diff --git a/ui/app/components/network-display.js b/ui/app/components/network-display.js index 9dc31b5c7..59719d9a4 100644 --- a/ui/app/components/network-display.js +++ b/ui/app/components/network-display.js @@ -1,9 +1,8 @@ const { Component } = require('react') const h = require('react-hyperscript') const PropTypes = require('prop-types') -const { connect } = require('react-redux') +const connect = require('react-redux').connect const NetworkDropdownIcon = require('./dropdowns/components/network-dropdown-icon') -const t = require('../../i18n') const networkToColorHash = { 1: '#038789', @@ -31,7 +30,7 @@ class NetworkDisplay extends Component { const { provider: { type } } = this.props return h('.network-display__container', [ this.renderNetworkIcon(), - h('.network-name', t(type)), + h('.network-name', this.context.t(type)), ]) } } @@ -39,6 +38,7 @@ class NetworkDisplay extends Component { NetworkDisplay.propTypes = { network: PropTypes.string, provider: PropTypes.object, + t: PropTypes.func, } const mapStateToProps = ({ metamask: { network, provider } }) => { @@ -48,4 +48,9 @@ const mapStateToProps = ({ metamask: { network, provider } }) => { } } +NetworkDisplay.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps)(NetworkDisplay) + diff --git a/ui/app/components/network.js b/ui/app/components/network.js index f3df2242a..83297c4f2 100644 --- a/ui/app/components/network.js +++ b/ui/app/components/network.js @@ -1,11 +1,17 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') +const connect = require('react-redux').connect const classnames = require('classnames') const inherits = require('util').inherits const NetworkDropdownIcon = require('./dropdowns/components/network-dropdown-icon') -const t = require('../../i18n') -module.exports = Network +Network.contextTypes = { + t: PropTypes.func, +} + +module.exports = connect()(Network) + inherits(Network, Component) @@ -15,6 +21,7 @@ function Network () { Network.prototype.render = function () { const props = this.props + const context = this.context const networkNumber = props.network let providerName try { @@ -34,7 +41,7 @@ Network.prototype.render = function () { onClick: (event) => this.props.onClick(event), }, [ h('img', { - title: t('attemptingConnect'), + title: context.t('attemptingConnect'), style: { width: '27px', }, @@ -42,22 +49,22 @@ Network.prototype.render = function () { }), ]) } else if (providerName === 'mainnet') { - hoverText = t('mainnet') + hoverText = context.t('mainnet') iconName = 'ethereum-network' } else if (providerName === 'ropsten') { - hoverText = t('ropsten') + hoverText = context.t('ropsten') iconName = 'ropsten-test-network' } else if (parseInt(networkNumber) === 3) { - hoverText = t('ropsten') + hoverText = context.t('ropsten') iconName = 'ropsten-test-network' } else if (providerName === 'kovan') { - hoverText = t('kovan') + hoverText = context.t('kovan') iconName = 'kovan-test-network' } else if (providerName === 'rinkeby') { - hoverText = t('rinkeby') + hoverText = context.t('rinkeby') iconName = 'rinkeby-test-network' } else { - hoverText = t('unknownNetwork') + hoverText = context.t('unknownNetwork') iconName = 'unknown-private-network' } @@ -85,7 +92,7 @@ Network.prototype.render = function () { backgroundColor: '#038789', // $blue-lagoon nonSelectBackgroundColor: '#15afb2', }), - h('.network-name', t('mainnet')), + h('.network-name', context.t('mainnet')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) case 'ropsten-test-network': @@ -94,7 +101,7 @@ Network.prototype.render = function () { backgroundColor: '#e91550', // $crimson nonSelectBackgroundColor: '#ec2c50', }), - h('.network-name', t('ropsten')), + h('.network-name', context.t('ropsten')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) case 'kovan-test-network': @@ -103,7 +110,7 @@ Network.prototype.render = function () { backgroundColor: '#690496', // $purple nonSelectBackgroundColor: '#b039f3', }), - h('.network-name', t('kovan')), + h('.network-name', context.t('kovan')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) case 'rinkeby-test-network': @@ -112,7 +119,7 @@ Network.prototype.render = function () { backgroundColor: '#ebb33f', // $tulip-tree nonSelectBackgroundColor: '#ecb23e', }), - h('.network-name', t('rinkeby')), + h('.network-name', context.t('rinkeby')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) default: @@ -124,7 +131,7 @@ Network.prototype.render = function () { }, }), - h('.network-name', t('privateNetwork')), + h('.network-name', context.t('privateNetwork')), h('i.fa.fa-chevron-down.fa-lg.network-caret'), ]) } diff --git a/ui/app/components/notice.js b/ui/app/components/notice.js index 8b0ce1e8b..bb7e0814c 100644 --- a/ui/app/components/notice.js +++ b/ui/app/components/notice.js @@ -1,12 +1,18 @@ const inherits = require('util').inherits const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const ReactMarkdown = require('react-markdown') const linker = require('extension-link-enabler') const findDOMNode = require('react-dom').findDOMNode -const t = require('../../i18n') +const connect = require('react-redux').connect + +Notice.contextTypes = { + t: PropTypes.func, +} + +module.exports = connect()(Notice) -module.exports = Notice inherits(Notice, Component) function Notice () { @@ -111,7 +117,7 @@ Notice.prototype.render = function () { style: { marginTop: '18px', }, - }, t('accept')), + }, this.context.t('accept')), ]) ) } diff --git a/ui/app/components/pending-msg-details.js b/ui/app/components/pending-msg-details.js index 87e66855d..f16fcb1c7 100644 --- a/ui/app/components/pending-msg-details.js +++ b/ui/app/components/pending-msg-details.js @@ -1,11 +1,17 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits -const t = require('../../i18n') +const connect = require('react-redux').connect const AccountPanel = require('./account-panel') -module.exports = PendingMsgDetails +PendingMsgDetails.contextTypes = { + t: PropTypes.func, +} + +module.exports = connect()(PendingMsgDetails) + inherits(PendingMsgDetails, Component) function PendingMsgDetails () { @@ -40,7 +46,7 @@ PendingMsgDetails.prototype.render = function () { // message data h('.tx-data.flex-column.flex-justify-center.flex-grow.select-none', [ h('.flex-column.flex-space-between', [ - h('label.font-small.allcaps', t('message')), + h('label.font-small.allcaps', this.context.t('message')), h('span.font-small', msgParams.data), ]), ]), diff --git a/ui/app/components/pending-msg.js b/ui/app/components/pending-msg.js index dc406b955..21a7864e4 100644 --- a/ui/app/components/pending-msg.js +++ b/ui/app/components/pending-msg.js @@ -1,10 +1,16 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const PendingTxDetails = require('./pending-msg-details') -const t = require('../../i18n') +const connect = require('react-redux').connect + +PendingMsg.contextTypes = { + t: PropTypes.func, +} + +module.exports = connect()(PendingMsg) -module.exports = PendingMsg inherits(PendingMsg, Component) function PendingMsg () { @@ -30,14 +36,14 @@ PendingMsg.prototype.render = function () { fontWeight: 'bold', textAlign: 'center', }, - }, t('signMessage')), + }, this.context.t('signMessage')), h('.error', { style: { margin: '10px', }, }, [ - t('signNotice'), + this.context.t('signNotice'), h('a', { href: 'https://medium.com/metamask/the-new-secure-way-to-sign-data-in-your-browser-6af9dd2a1527', style: { color: 'rgb(247, 134, 28)' }, @@ -46,7 +52,7 @@ PendingMsg.prototype.render = function () { const url = 'https://medium.com/metamask/the-new-secure-way-to-sign-data-in-your-browser-6af9dd2a1527' global.platform.openWindow({ url }) }, - }, t('readMore')), + }, this.context.t('readMore')), ]), // message details @@ -56,10 +62,10 @@ PendingMsg.prototype.render = function () { h('.flex-row.flex-space-around', [ h('button', { onClick: state.cancelMessage, - }, t('cancel')), + }, this.context.t('cancel')), h('button', { onClick: state.signMessage, - }, t('sign')), + }, this.context.t('sign')), ]), ]) diff --git a/ui/app/components/pending-tx/confirm-deploy-contract.js b/ui/app/components/pending-tx/confirm-deploy-contract.js index b75f3a964..aa68a9eb0 100644 --- a/ui/app/components/pending-tx/confirm-deploy-contract.js +++ b/ui/app/components/pending-tx/confirm-deploy-contract.js @@ -1,5 +1,5 @@ const { Component } = require('react') -const { connect } = require('react-redux') +const connect = require('react-redux').connect const h = require('react-hyperscript') const PropTypes = require('prop-types') const actions = require('../../actions') @@ -8,7 +8,6 @@ const ethUtil = require('ethereumjs-util') const BN = ethUtil.BN const hexToBn = require('../../../../app/scripts/lib/hex-to-bn') const { conversionUtil } = require('../../conversion-util') -const t = require('../../../i18n') const SenderToRecipient = require('../sender-to-recipient') const NetworkDisplay = require('../network-display') @@ -33,7 +32,7 @@ class ConfirmDeployContract extends Component { if (valid && this.verifyGasParams()) { this.props.sendTransaction(txMeta, event) } else { - this.props.displayWarning('invalidGasParams') + this.props.displayWarning(this.context.t('invalidGasParams')) this.setState({ submitting: false }) } } @@ -178,7 +177,7 @@ class ConfirmDeployContract extends Component { return ( h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t('gasFee') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('gasFee') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', `${fiatGas} ${currentCurrency.toUpperCase()}`), @@ -217,8 +216,8 @@ class ConfirmDeployContract extends Component { return ( h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [ h('div.confirm-screen-section-column', [ - h('span.confirm-screen-label', [ t('total') + ' ' ]), - h('div.confirm-screen-total-box__subtitle', [ t('amountPlusGas') ]), + h('span.confirm-screen-label', [ this.context.t('total') + ' ' ]), + h('div.confirm-screen-total-box__subtitle', [ this.context.t('amountPlusGas') ]), ]), h('div.confirm-screen-section-column', [ @@ -248,11 +247,11 @@ class ConfirmDeployContract extends Component { h('.page-container__header-row', [ h('span.page-container__back-button', { onClick: () => backToAccountDetail(selectedAddress), - }, t('back')), + }, this.context.t('back')), window.METAMASK_UI_TYPE === 'notification' && h(NetworkDisplay), ]), - h('.page-container__title', t('confirmContract')), - h('.page-container__subtitle', t('pleaseReviewTransaction')), + h('.page-container__title', this.context.t('confirmContract')), + h('.page-container__subtitle', this.context.t('pleaseReviewTransaction')), ]), // Main Send token Card h('.page-container__content', [ @@ -275,7 +274,7 @@ class ConfirmDeployContract extends Component { h('div.confirm-screen-rows', [ h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t('from') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('from') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', fromName), h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`), @@ -283,9 +282,9 @@ class ConfirmDeployContract extends Component { ]), h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t('to') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('to') ]), h('div.confirm-screen-section-column', [ - h('div.confirm-screen-row-info', t('newContract')), + h('div.confirm-screen-row-info', this.context.t('newContract')), ]), ]), @@ -303,12 +302,12 @@ class ConfirmDeployContract extends Component { // Cancel Button h('button.btn-cancel.page-container__footer-button.allcaps', { onClick: event => this.cancel(event, txMeta), - }, t('cancel')), + }, this.context.t('cancel')), // Accept Button h('button.btn-confirm.page-container__footer-button.allcaps', { onClick: event => this.onSubmit(event), - }, t('confirm')), + }, this.context.t('confirm')), ]), ]), ]) @@ -325,6 +324,7 @@ ConfirmDeployContract.propTypes = { conversionRate: PropTypes.number, currentCurrency: PropTypes.string, selectedAddress: PropTypes.string, + t: PropTypes.func, } const mapStateToProps = state => { @@ -347,8 +347,12 @@ const mapDispatchToProps = dispatch => { return { backToAccountDetail: address => dispatch(actions.backToAccountDetail(address)), cancelTransaction: ({ id }) => dispatch(actions.cancelTx({ id })), - displayWarning: warning => actions.displayWarning(t(warning)), + displayWarning: warning => actions.displayWarning(warning), } } +ConfirmDeployContract.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(ConfirmDeployContract) diff --git a/ui/app/components/pending-tx/confirm-send-ether.js b/ui/app/components/pending-tx/confirm-send-ether.js index d1ce25cbf..d007e6661 100644 --- a/ui/app/components/pending-tx/confirm-send-ether.js +++ b/ui/app/components/pending-tx/confirm-send-ether.js @@ -1,5 +1,6 @@ const Component = require('react').Component -const { connect } = require('react-redux') +const PropTypes = require('prop-types') +const connect = require('react-redux').connect const h = require('react-hyperscript') const inherits = require('util').inherits const actions = require('../../actions') @@ -7,20 +8,29 @@ const clone = require('clone') const ethUtil = require('ethereumjs-util') const BN = ethUtil.BN const hexToBn = require('../../../../app/scripts/lib/hex-to-bn') +const classnames = require('classnames') const { conversionUtil, addCurrencies, multiplyCurrencies, } = require('../../conversion-util') +const { + getGasTotal, + isBalanceSufficient, +} = require('../send/send-utils') const GasFeeDisplay = require('../send/gas-fee-display-v2') -const t = require('../../../i18n') const SenderToRecipient = require('../sender-to-recipient') const NetworkDisplay = require('../network-display') const { MIN_GAS_PRICE_HEX } = require('../send/send-constants') +ConfirmSendEther.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(ConfirmSendEther) + function mapStateToProps (state) { const { conversionRate, @@ -30,12 +40,14 @@ function mapStateToProps (state) { } = state.metamask const accounts = state.metamask.accounts const selectedAddress = state.metamask.selectedAddress || Object.keys(accounts)[0] + const { balance } = accounts[selectedAddress] return { conversionRate, identities, selectedAddress, currentCurrency, send, + balance, } } @@ -86,6 +98,7 @@ function mapDispatchToProps (dispatch) { })) dispatch(actions.showModal({ name: 'CUSTOMIZE_GAS' })) }, + updateSendErrors: error => dispatch(actions.updateSendErrors(error)), } } @@ -96,6 +109,52 @@ function ConfirmSendEther () { this.onSubmit = this.onSubmit.bind(this) } +ConfirmSendEther.prototype.updateComponentSendErrors = function (prevProps) { + const { + balance: oldBalance, + conversionRate: oldConversionRate, + } = prevProps + const { + updateSendErrors, + balance, + conversionRate, + send: { + errors: { + simulationFails, + }, + }, + } = this.props + const txMeta = this.gatherTxMeta() + + const shouldUpdateBalanceSendErrors = balance && [ + balance !== oldBalance, + conversionRate !== oldConversionRate, + ].some(x => Boolean(x)) + + if (shouldUpdateBalanceSendErrors) { + const balanceIsSufficient = this.isBalanceSufficient(txMeta) + updateSendErrors({ + insufficientFunds: balanceIsSufficient ? false : this.context.t('insufficientFunds'), + }) + } + + const shouldUpdateSimulationSendError = Boolean(txMeta.simulationFails) !== Boolean(simulationFails) + + if (shouldUpdateSimulationSendError) { + updateSendErrors({ + simulationFails: !txMeta.simulationFails ? false : this.context.t('transactionError'), + }) + } +} + +ConfirmSendEther.prototype.componentWillMount = function () { + this.updateComponentSendErrors({}) +} + +ConfirmSendEther.prototype.componentDidUpdate = function (prevProps) { + this.updateComponentSendErrors(prevProps) +} + ConfirmSendEther.prototype.getAmount = function () { const { conversionRate, currentCurrency } = this.props const txMeta = this.gatherTxMeta() @@ -197,7 +256,7 @@ ConfirmSendEther.prototype.getData = function () { }, to: { address: txParams.to, - name: identities[txParams.to] ? identities[txParams.to].name : t('newRecipient'), + name: identities[txParams.to] ? identities[txParams.to].name : this.context.t('newRecipient'), }, memo: txParams.memo || '', gasFeeInFIAT, @@ -218,7 +277,12 @@ ConfirmSendEther.prototype.render = function () { conversionRate, currentCurrency: convertedCurrency, showCustomizeGasModal, - send: { gasTotal, gasLimit: sendGasLimit, gasPrice: sendGasPrice }, + send: { + gasTotal, + gasLimit: sendGasLimit, + gasPrice: sendGasPrice, + errors, + }, } = this.props const txMeta = this.gatherTxMeta() const txParams = txMeta.txParams || {} @@ -298,7 +362,7 @@ ConfirmSendEther.prototype.render = function () { h('div.confirm-screen-rows', [ h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t('from') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('from') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', fromName), h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`), @@ -306,7 +370,7 @@ ConfirmSendEther.prototype.render = function () { ]), h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t('to') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('to') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', toName), h('div.confirm-screen-row-detail', `...${toAddress.slice(toAddress.length - 4)}`), @@ -314,7 +378,7 @@ ConfirmSendEther.prototype.render = function () { ]), h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t('gasFee') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('gasFee') ]), h('div.confirm-screen-section-column', [ h(GasFeeDisplay, { gasTotal: gasTotal || gasFeeInHex, @@ -326,15 +390,22 @@ ConfirmSendEther.prototype.render = function () { ]), h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [ - h('div.confirm-screen-section-column', [ - h('span.confirm-screen-label', [ t('total') + ' ' ]), - h('div.confirm-screen-total-box__subtitle', [ t('amountPlusGas') ]), + h('div', { + className: classnames({ + 'confirm-screen-section-column--with-error': errors['insufficientFunds'], + 'confirm-screen-section-column': !errors['insufficientFunds'], + }), + }, [ + h('span.confirm-screen-label', [ this.context.t('total') + ' ' ]), + h('div.confirm-screen-total-box__subtitle', [ this.context.t('amountPlusGas') ]), ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', `${totalInFIAT} ${currentCurrency.toUpperCase()}`), h('div.confirm-screen-row-detail', `${totalInETH} ETH`), ]), + + this.renderErrorMessage('insufficientFunds'), ]), ]), @@ -420,8 +491,10 @@ ConfirmSendEther.prototype.render = function () { ]), h('form#pending-tx-form', { + className: 'confirm-screen-form', onSubmit: this.onSubmit, }, [ + this.renderErrorMessage('simulationFails'), h('.page-container__footer', [ // Cancel Button h('button.btn-cancel.page-container__footer-button.allcaps', { @@ -429,26 +502,38 @@ ConfirmSendEther.prototype.render = function () { clearSend() this.cancel(event, txMeta) }, - }, t('cancel')), + }, this.context.t('cancel')), // Accept Button - h('button.btn-confirm.page-container__footer-button.allcaps', [t('confirm')]), + h('button.btn-confirm.page-container__footer-button.allcaps', [this.context.t('confirm')]), ]), ]), ]) ) } +ConfirmSendEther.prototype.renderErrorMessage = function (message) { + const { send: { errors } } = this.props + + return errors[message] + ? h('div.confirm-screen-error', [ errors[message] ]) + : null +} + ConfirmSendEther.prototype.onSubmit = function (event) { event.preventDefault() + const { updateSendErrors } = this.props const txMeta = this.gatherTxMeta() const valid = this.checkValidity() + const balanceIsSufficient = this.isBalanceSufficient(txMeta) this.setState({ valid, submitting: true }) - if (valid && this.verifyGasParams()) { + if (valid && this.verifyGasParams() && balanceIsSufficient) { this.props.sendTransaction(txMeta, event) + } else if (!balanceIsSufficient) { + updateSendErrors({ insufficientFunds: this.context.t('insufficientFunds') }) } else { - this.props.dispatch(actions.displayWarning(t('invalidGasParams'))) + updateSendErrors({ invalidGasParams: this.context.t('invalidGasParams') }) this.setState({ submitting: false }) } } @@ -460,6 +545,28 @@ ConfirmSendEther.prototype.cancel = function (event, txMeta) { cancelTransaction(txMeta) } +ConfirmSendEther.prototype.isBalanceSufficient = function (txMeta) { + const { + balance, + conversionRate, + } = this.props + const { + txParams: { + gas, + gasPrice, + value: amount, + }, + } = txMeta + const gasTotal = getGasTotal(gas, gasPrice) + + return isBalanceSufficient({ + amount, + gasTotal, + balance, + conversionRate, + }) +} + ConfirmSendEther.prototype.checkValidity = function () { const form = this.getFormEl() const valid = form.checkValidity() @@ -523,4 +630,4 @@ ConfirmSendEther.prototype.bnMultiplyByFraction = function (targetBN, numerator, const numBN = new BN(numerator) const denomBN = new BN(denominator) return targetBN.mul(numBN).div(denomBN) -} +}
\ No newline at end of file diff --git a/ui/app/components/pending-tx/confirm-send-token.js b/ui/app/components/pending-tx/confirm-send-token.js index f9276e8a5..19e591fd6 100644 --- a/ui/app/components/pending-tx/confirm-send-token.js +++ b/ui/app/components/pending-tx/confirm-send-token.js @@ -1,12 +1,12 @@ const Component = require('react').Component -const { connect } = require('react-redux') +const PropTypes = require('prop-types') +const connect = require('react-redux').connect const h = require('react-hyperscript') const inherits = require('util').inherits const tokenAbi = require('human-standard-token-abi') const abiDecoder = require('abi-decoder') abiDecoder.addABI(tokenAbi) const actions = require('../../actions') -const t = require('../../../i18n') const clone = require('clone') const Identicon = require('../identicon') const GasFeeDisplay = require('../send/gas-fee-display-v2.js') @@ -18,8 +18,13 @@ const { addCurrencies, } = require('../../conversion-util') const { + getGasTotal, + isBalanceSufficient, +} = require('../send/send-utils') +const { calcTokenAmount, } = require('../../token-util') +const classnames = require('classnames') const { MIN_GAS_PRICE_HEX } = require('../send/send-constants') @@ -29,8 +34,13 @@ const { getSelectedTokenContract, } = require('../../selectors') +ConfirmSendToken.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(ConfirmSendToken) + function mapStateToProps (state, ownProps) { const { token: { symbol }, txData } = ownProps const { txParams } = txData || {} @@ -41,9 +51,10 @@ function mapStateToProps (state, ownProps) { identities, currentCurrency, } = state.metamask + const accounts = state.metamask.accounts const selectedAddress = getSelectedAddress(state) const tokenExchangeRate = getTokenExchangeRate(state, symbol) - + const { balance } = accounts[selectedAddress] return { conversionRate, identities, @@ -53,6 +64,7 @@ function mapStateToProps (state, ownProps) { currentCurrency: currentCurrency.toUpperCase(), send: state.metamask.send, tokenContract: getSelectedTokenContract(state), + balance, } } @@ -102,7 +114,7 @@ function mapDispatchToProps (dispatch, ownProps) { fromNumericBase: 'dec', toNumericBase: 'hex', }) - + let forceGasMin if (lastGasPrice) { forceGasMin = ethUtil.addHexPrefix(multiplyCurrencies(lastGasPrice, 1.1, { @@ -124,6 +136,7 @@ function mapDispatchToProps (dispatch, ownProps) { })) dispatch(actions.showModal({ name: 'CUSTOMIZE_GAS' })) }, + updateSendErrors: error => dispatch(actions.updateSendErrors(error)), } } @@ -134,6 +147,44 @@ function ConfirmSendToken () { this.onSubmit = this.onSubmit.bind(this) } +ConfirmSendToken.prototype.updateComponentSendErrors = function (prevProps) { + const { + balance: oldBalance, + conversionRate: oldConversionRate, + } = prevProps + const { + updateSendErrors, + balance, + conversionRate, + send: { + errors: { + simulationFails, + }, + }, + } = this.props + const txMeta = this.gatherTxMeta() + + const shouldUpdateBalanceSendErrors = balance && [ + balance !== oldBalance, + conversionRate !== oldConversionRate, + ].some(x => Boolean(x)) + + if (shouldUpdateBalanceSendErrors) { + const balanceIsSufficient = this.isBalanceSufficient(txMeta) + updateSendErrors({ + insufficientFunds: balanceIsSufficient ? false : this.context.t('insufficientFunds'), + }) + } + + const shouldUpdateSimulationSendError = Boolean(txMeta.simulationFails) !== Boolean(simulationFails) + + if (shouldUpdateSimulationSendError) { + updateSendErrors({ + simulationFails: !txMeta.simulationFails ? false : this.context.t('transactionError'), + }) + } +} + ConfirmSendToken.prototype.componentWillMount = function () { const { tokenContract, selectedAddress } = this.props tokenContract && tokenContract @@ -141,6 +192,11 @@ ConfirmSendToken.prototype.componentWillMount = function () { .then(usersToken => { }) this.props.updateTokenExchangeRate() + this.updateComponentSendErrors({}) +} + +ConfirmSendToken.prototype.componentDidUpdate = function (prevProps) { + this.updateComponentSendErrors(prevProps) } ConfirmSendToken.prototype.getAmount = function () { @@ -169,7 +225,7 @@ ConfirmSendToken.prototype.getAmount = function () { ? +(sendTokenAmount * tokenExchangeRate * conversionRate).toFixed(2) : null, token: typeof value === 'undefined' - ? t('unknown') + ? this.context.t('unknown') : +sendTokenAmount.toFixed(decimals), } @@ -241,7 +297,7 @@ ConfirmSendToken.prototype.getData = function () { }, to: { address: value, - name: identities[value] ? identities[value].name : t('newRecipient'), + name: identities[value] ? identities[value].name : this.context.t('newRecipient'), }, memo: txParams.memo || '', } @@ -287,7 +343,7 @@ ConfirmSendToken.prototype.renderGasFee = function () { return ( h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t('gasFee') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('gasFee') ]), h('div.confirm-screen-section-column', [ h(GasFeeDisplay, { gasTotal: gasTotal || gasFeeInHex, @@ -301,7 +357,7 @@ ConfirmSendToken.prototype.renderGasFee = function () { } ConfirmSendToken.prototype.renderTotalPlusGas = function () { - const { token: { symbol }, currentCurrency } = this.props + const { token: { symbol }, currentCurrency, send: { errors } } = this.props const { fiat: fiatAmount, token: tokenAmount } = this.getAmount() const { fiat: fiatGas, token: tokenGas } = this.getGasFee() @@ -309,8 +365,8 @@ ConfirmSendToken.prototype.renderTotalPlusGas = function () { ? ( h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [ h('div.confirm-screen-section-column', [ - h('span.confirm-screen-label', [ t('total') + ' ' ]), - h('div.confirm-screen-total-box__subtitle', [ t('amountPlusGas') ]), + h('span.confirm-screen-label', [ this.context.t('total') + ' ' ]), + h('div.confirm-screen-total-box__subtitle', [ this.context.t('amountPlusGas') ]), ]), h('div.confirm-screen-section-column', [ @@ -321,19 +377,34 @@ ConfirmSendToken.prototype.renderTotalPlusGas = function () { ) : ( h('section.flex-row.flex-center.confirm-screen-row.confirm-screen-total-box ', [ - h('div.confirm-screen-section-column', [ - h('span.confirm-screen-label', [ t('total') + ' ' ]), - h('div.confirm-screen-total-box__subtitle', [ t('amountPlusGas') ]), + h('div', { + className: classnames({ + 'confirm-screen-section-column--with-error': errors['insufficientFunds'], + 'confirm-screen-section-column': !errors['insufficientFunds'], + }), + }, [ + h('span.confirm-screen-label', [ this.context.t('total') + ' ' ]), + h('div.confirm-screen-total-box__subtitle', [ this.context.t('amountPlusGas') ]), ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', `${tokenAmount} ${symbol}`), - h('div.confirm-screen-row-detail', `+ ${fiatGas} ${currentCurrency} ${t('gas')}`), + h('div.confirm-screen-row-detail', `+ ${fiatGas} ${currentCurrency} ${this.context.t('gas')}`), ]), + + this.renderErrorMessage('insufficientFunds'), ]) ) } +ConfirmSendToken.prototype.renderErrorMessage = function (message) { + const { send: { errors } } = this.props + + return errors[message] + ? h('div.confirm-screen-error', [ errors[message] ]) + : null +} + ConfirmSendToken.prototype.render = function () { const { editTransaction } = this.props const txMeta = this.gatherTxMeta() @@ -350,10 +421,11 @@ ConfirmSendToken.prototype.render = function () { this.inputs = [] - const title = txMeta.lastGasPrice ? 'Reprice Transaction' : t('confirm') - const subtitle = txMeta.lastGasPrice - ? 'Increase your gas fee to attempt to overwrite and speed up your transaction' - : t('pleaseReviewTransaction') + const isTxReprice = Boolean(txMeta.lastGasPrice) + const title = isTxReprice ? this.context.t('reprice_title') : this.context.t('confirm') + const subtitle = isTxReprice + ? this.context.t('reprice_subtitle') + : this.context.t('pleaseReviewTransaction') return ( h('div.confirm-screen-container.confirm-send-token', [ @@ -362,7 +434,7 @@ ConfirmSendToken.prototype.render = function () { h('div.page-container__header', [ !txMeta.lastGasPrice && h('button.confirm-screen-back-button', { onClick: () => editTransaction(txMeta), - }, t('edit')), + }, this.context.t('edit')), h('div.page-container__title', title), h('div.page-container__subtitle', subtitle), ]), @@ -406,7 +478,7 @@ ConfirmSendToken.prototype.render = function () { h('div.confirm-screen-rows', [ h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t('from') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('from') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', fromName), h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`), @@ -414,7 +486,7 @@ ConfirmSendToken.prototype.render = function () { ]), toAddress && h('section.flex-row.flex-center.confirm-screen-row', [ - h('span.confirm-screen-label.confirm-screen-section-column', [ t('to') ]), + h('span.confirm-screen-label.confirm-screen-section-column', [ this.context.t('to') ]), h('div.confirm-screen-section-column', [ h('div.confirm-screen-row-info', toName), h('div.confirm-screen-row-detail', `...${toAddress.slice(toAddress.length - 4)}`), @@ -428,17 +500,20 @@ ConfirmSendToken.prototype.render = function () { ]), ]), + h('form#pending-tx-form', { + className: 'confirm-screen-form', onSubmit: this.onSubmit, }, [ + this.renderErrorMessage('simulationFails'), h('.page-container__footer', [ // Cancel Button h('button.btn-cancel.page-container__footer-button.allcaps', { onClick: (event) => this.cancel(event, txMeta), - }, t('cancel')), + }, this.context.t('cancel')), // Accept Button - h('button.btn-confirm.page-container__footer-button.allcaps', [t('confirm')]), + h('button.btn-confirm.page-container__footer-button.allcaps', [this.context.t('confirm')]), ]), ]), ]), @@ -448,18 +523,44 @@ ConfirmSendToken.prototype.render = function () { ConfirmSendToken.prototype.onSubmit = function (event) { event.preventDefault() + const { updateSendErrors } = this.props const txMeta = this.gatherTxMeta() const valid = this.checkValidity() + const balanceIsSufficient = this.isBalanceSufficient(txMeta) this.setState({ valid, submitting: true }) - if (valid && this.verifyGasParams()) { + if (valid && this.verifyGasParams() && balanceIsSufficient) { this.props.sendTransaction(txMeta, event) + } else if (!balanceIsSufficient) { + updateSendErrors({ insufficientFunds: this.context.t('insufficientFunds') }) } else { - this.props.dispatch(actions.displayWarning(t('invalidGasParams'))) + updateSendErrors({ invalidGasParams: this.context.t('invalidGasParams') }) this.setState({ submitting: false }) } } +ConfirmSendToken.prototype.isBalanceSufficient = function (txMeta) { + const { + balance, + conversionRate, + } = this.props + const { + txParams: { + gas, + gasPrice, + }, + } = txMeta + const gasTotal = getGasTotal(gas, gasPrice) + + return isBalanceSufficient({ + amount: '0', + gasTotal, + balance, + conversionRate, + }) +} + + ConfirmSendToken.prototype.cancel = function (event, txMeta) { event.preventDefault() const { cancelTransaction } = this.props diff --git a/ui/app/components/pending-tx/index.js b/ui/app/components/pending-tx/index.js index 9c0453a3b..acdd99364 100644 --- a/ui/app/components/pending-tx/index.js +++ b/ui/app/components/pending-tx/index.js @@ -1,5 +1,5 @@ const Component = require('react').Component -const { connect } = require('react-redux') +const connect = require('react-redux').connect const h = require('react-hyperscript') const clone = require('clone') const abi = require('human-standard-token-abi') diff --git a/ui/app/components/send/gas-fee-display-v2.js b/ui/app/components/send/gas-fee-display-v2.js index f6af13454..1423aa84d 100644 --- a/ui/app/components/send/gas-fee-display-v2.js +++ b/ui/app/components/send/gas-fee-display-v2.js @@ -1,10 +1,16 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const CurrencyDisplay = require('./currency-display') -const t = require('../../../i18n') +const connect = require('react-redux').connect + +GasFeeDisplay.contextTypes = { + t: PropTypes.func, +} + +module.exports = connect()(GasFeeDisplay) -module.exports = GasFeeDisplay inherits(GasFeeDisplay, Component) function GasFeeDisplay () { @@ -33,8 +39,8 @@ GasFeeDisplay.prototype.render = function () { readOnly: true, }) : gasLoadingError - ? h('div..currency-display.currency-display--message', 'Set with the gas price customizer.') - : h('div.currency-display', t('loading')), + ? h('div.currency-display.currency-display--message', this.context.t('setGasPrice')) + : h('div.currency-display', this.context.t('loading')), h('button.sliders-icon-container', { onClick, diff --git a/ui/app/components/send/gas-tooltip.js b/ui/app/components/send/gas-tooltip.js index d925d3ed8..62cdc1cad 100644 --- a/ui/app/components/send/gas-tooltip.js +++ b/ui/app/components/send/gas-tooltip.js @@ -1,10 +1,16 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const InputNumber = require('../input-number.js') -const t = require('../../../i18n') +const connect = require('react-redux').connect + +GasTooltip.contextTypes = { + t: PropTypes.func, +} + +module.exports = connect()(GasTooltip) -module.exports = GasTooltip inherits(GasTooltip, Component) function GasTooltip () { @@ -82,7 +88,7 @@ GasTooltip.prototype.render = function () { 'marginTop': '81px', }, }, [ - h('span.gas-tooltip-label', {}, [t('gasLimit')]), + h('span.gas-tooltip-label', {}, [this.context.t('gasLimit')]), h('i.fa.fa-info-circle'), ]), h(InputNumber, { diff --git a/ui/app/components/send/send-utils.js b/ui/app/components/send/send-utils.js index d8211930d..71bfb2668 100644 --- a/ui/app/components/send/send-utils.js +++ b/ui/app/components/send/send-utils.js @@ -2,6 +2,7 @@ const { addCurrencies, conversionUtil, conversionGTE, + multiplyCurrencies, } = require('../../conversion-util') const { calcTokenAmount, @@ -31,7 +32,7 @@ function isBalanceSufficient ({ { value: totalAmount, fromNumericBase: 'hex', - conversionRate: amountConversionRate, + conversionRate: amountConversionRate || conversionRate, fromCurrency: primaryCurrency, }, ) @@ -62,7 +63,16 @@ function isTokenBalanceSufficient ({ return tokenBalanceIsSufficient } +function getGasTotal (gasLimit, gasPrice) { + return multiplyCurrencies(gasLimit, gasPrice, { + toNumericBase: 'hex', + multiplicandBase: 16, + multiplierBase: 16, + }) +} + module.exports = { + getGasTotal, isBalanceSufficient, isTokenBalanceSufficient, } diff --git a/ui/app/components/send/to-autocomplete.js b/ui/app/components/send/to-autocomplete.js index 72074229e..5ea17f9a2 100644 --- a/ui/app/components/send/to-autocomplete.js +++ b/ui/app/components/send/to-autocomplete.js @@ -1,10 +1,16 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const AccountListItem = require('./account-list-item') -const t = require('../../../i18n') +const connect = require('react-redux').connect + +ToAutoComplete.contextTypes = { + t: PropTypes.func, +} + +module.exports = connect()(ToAutoComplete) -module.exports = ToAutoComplete inherits(ToAutoComplete, Component) function ToAutoComplete () { @@ -93,7 +99,7 @@ ToAutoComplete.prototype.render = function () { return h('div.send-v2__to-autocomplete', {}, [ h('input.send-v2__to-autocomplete__input', { - placeholder: t('recipientAddress'), + placeholder: this.context.t('recipientAddress'), className: inError ? `send-v2__error-border` : '', value: to, onChange: event => onChange(event.target.value), diff --git a/ui/app/components/sender-to-recipient.js b/ui/app/components/sender-to-recipient.js index f35c353ad..9cef8e401 100644 --- a/ui/app/components/sender-to-recipient.js +++ b/ui/app/components/sender-to-recipient.js @@ -1,7 +1,7 @@ const { Component } = require('react') const h = require('react-hyperscript') +const connect = require('react-redux').connect const PropTypes = require('prop-types') -const t = require('../../i18n') const Identicon = require('./identicon') class SenderToRecipient extends Component { @@ -21,7 +21,7 @@ class SenderToRecipient extends Component { this.renderRecipientIcon(), h( '.sender-to-recipient__name.sender-to-recipient__recipient-name', - recipientName || t('newContract') + recipientName || this.context.t('newContract') ), ]) ) @@ -46,7 +46,7 @@ class SenderToRecipient extends Component { h('img', { height: 15, width: 15, - src: '/images/arrow-right.svg', + src: './images/arrow-right.svg', }), ]), ]), @@ -61,6 +61,12 @@ SenderToRecipient.propTypes = { senderAddress: PropTypes.string, recipientName: PropTypes.string, recipientAddress: PropTypes.string, + t: PropTypes.func, } -module.exports = SenderToRecipient +SenderToRecipient.contextTypes = { + t: PropTypes.func, +} + +module.exports = connect()(SenderToRecipient) + diff --git a/ui/app/components/shapeshift-form.js b/ui/app/components/shapeshift-form.js index 5729f893c..fd4a80a4a 100644 --- a/ui/app/components/shapeshift-form.js +++ b/ui/app/components/shapeshift-form.js @@ -1,5 +1,6 @@ const h = require('react-hyperscript') const inherits = require('util').inherits +const PropTypes = require('prop-types') const Component = require('react').Component const connect = require('react-redux').connect const classnames = require('classnames') @@ -7,7 +8,6 @@ const { qrcode } = require('qrcode-npm') const { shapeShiftSubview, pairUpdate, buyWithShapeShift } = require('../actions') const { isValidAddress } = require('../util') const SimpleDropdown = require('./dropdowns/simple-dropdown') -const t = require('../../i18n') function mapStateToProps (state) { const { @@ -33,8 +33,13 @@ function mapDispatchToProps (dispatch) { } } +ShapeshiftForm.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(ShapeshiftForm) + inherits(ShapeshiftForm, Component) function ShapeshiftForm () { Component.call(this) @@ -94,7 +99,7 @@ ShapeshiftForm.prototype.onBuyWithShapeShift = function () { })) .catch(() => this.setState({ showQrCode: false, - errorMessage: t('invalidRequest'), + errorMessage: this.context.t('invalidRequest'), isLoading: false, })) } @@ -126,10 +131,10 @@ ShapeshiftForm.prototype.renderMarketInfo = function () { return h('div.shapeshift-form__metadata', {}, [ - this.renderMetadata(t('status'), limit ? t('available') : t('unavailable')), - this.renderMetadata(t('limit'), limit), - this.renderMetadata(t('exchangeRate'), rate), - this.renderMetadata(t('min'), minimum), + this.renderMetadata(this.context.t('status'), limit ? this.context.t('available') : this.context.t('unavailable')), + this.renderMetadata(this.context.t('limit'), limit), + this.renderMetadata(this.context.t('exchangeRate'), rate), + this.renderMetadata(this.context.t('min'), minimum), ]) } @@ -143,7 +148,7 @@ ShapeshiftForm.prototype.renderQrCode = function () { return h('div.shapeshift-form', {}, [ h('div.shapeshift-form__deposit-instruction', [ - t('depositCoin', [depositCoin.toUpperCase()]), + this.context.t('depositCoin', [depositCoin.toUpperCase()]), ]), h('div', depositAddress), @@ -180,7 +185,7 @@ ShapeshiftForm.prototype.render = function () { h('div.shapeshift-form__selector', [ - h('div.shapeshift-form__selector-label', t('deposit')), + h('div.shapeshift-form__selector-label', this.context.t('deposit')), h(SimpleDropdown, { selectedOption: this.state.depositCoin, @@ -200,7 +205,7 @@ ShapeshiftForm.prototype.render = function () { h('div.shapeshift-form__selector', [ h('div.shapeshift-form__selector-label', [ - t('receive'), + this.context.t('receive'), ]), h('div.shapeshift-form__selector-input', ['ETH']), @@ -218,7 +223,7 @@ ShapeshiftForm.prototype.render = function () { }, [ h('div.shapeshift-form__address-input-label', [ - t('refundAddress'), + this.context.t('refundAddress'), ]), h('input.shapeshift-form__address-input', { @@ -240,7 +245,7 @@ ShapeshiftForm.prototype.render = function () { className: btnClass, disabled: !token, onClick: () => this.onBuyWithShapeShift(), - }, [t('buy')]), + }, [this.context.t('buy')]), ]) } diff --git a/ui/app/components/shift-list-item.js b/ui/app/components/shift-list-item.js index fddbc6821..4334aacba 100644 --- a/ui/app/components/shift-list-item.js +++ b/ui/app/components/shift-list-item.js @@ -1,20 +1,25 @@ const inherits = require('util').inherits const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const connect = require('react-redux').connect const vreme = new (require('vreme'))() const explorerLink = require('etherscan-link').createExplorerLink const actions = require('../actions') const addressSummary = require('../util').addressSummary -const t = require('../../i18n') const CopyButton = require('./copyButton') const EthBalance = require('./eth-balance') const Tooltip = require('./tooltip') +ShiftListItem.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps)(ShiftListItem) + function mapStateToProps (state) { return { selectedAddress: state.metamask.selectedAddress, @@ -76,7 +81,7 @@ ShiftListItem.prototype.renderUtilComponents = function () { value: this.props.depositAddress, }), h(Tooltip, { - title: t('qrCode'), + title: this.context.t('qrCode'), }, [ h('i.fa.fa-qrcode.pointer.pop-hover', { onClick: () => props.dispatch(actions.reshowQrCode(props.depositAddress, props.depositType)), @@ -136,8 +141,8 @@ ShiftListItem.prototype.renderInfo = function () { color: '#ABA9AA', width: '100%', }, - }, t('toETHviaShapeShift', [props.depositType])), - h('div', t('noDeposits')), + }, this.context.t('toETHviaShapeShift', [props.depositType])), + h('div', this.context.t('noDeposits')), h('div', { style: { fontSize: 'x-small', @@ -159,8 +164,8 @@ ShiftListItem.prototype.renderInfo = function () { color: '#ABA9AA', width: '100%', }, - }, t('toETHviaShapeShift', [props.depositType])), - h('div', t('conversionProgress')), + }, this.context.t('toETHviaShapeShift', [props.depositType])), + h('div', this.context.t('conversionProgress')), h('div', { style: { fontSize: 'x-small', @@ -185,7 +190,7 @@ ShiftListItem.prototype.renderInfo = function () { color: '#ABA9AA', width: '100%', }, - }, t('fromShapeShift')), + }, this.context.t('fromShapeShift')), h('div', formatDate(props.time)), h('div', { style: { @@ -197,7 +202,7 @@ ShiftListItem.prototype.renderInfo = function () { ]) case 'failed': - return h('span.error', '(' + t('failed') + ')') + return h('span.error', '(' + this.context.t('failed') + ')') default: return '' } diff --git a/ui/app/components/signature-request.js b/ui/app/components/signature-request.js index 810a52e55..41415411e 100644 --- a/ui/app/components/signature-request.js +++ b/ui/app/components/signature-request.js @@ -1,4 +1,5 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const Identicon = require('./identicon') @@ -9,7 +10,6 @@ const classnames = require('classnames') const AccountDropdownMini = require('./dropdowns/account-dropdown-mini') const actions = require('../actions') -const t = require('../../i18n') const { conversionUtil } = require('../conversion-util') const { @@ -38,8 +38,13 @@ function mapDispatchToProps (dispatch) { } } +SignatureRequest.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(SignatureRequest) + inherits(SignatureRequest, Component) function SignatureRequest (props) { Component.call(this) @@ -55,7 +60,7 @@ SignatureRequest.prototype.renderHeader = function () { h('div.request-signature__header-background'), - h('div.request-signature__header__text', t('sigRequest')), + h('div.request-signature__header__text', this.context.t('sigRequest')), h('div.request-signature__header__tip-container', [ h('div.request-signature__header__tip'), @@ -76,7 +81,7 @@ SignatureRequest.prototype.renderAccountDropdown = function () { return h('div.request-signature__account', [ - h('div.request-signature__account-text', [t('account') + ':']), + h('div.request-signature__account-text', [this.context.t('account') + ':']), h(AccountDropdownMini, { selectedAccount, @@ -103,7 +108,7 @@ SignatureRequest.prototype.renderBalance = function () { return h('div.request-signature__balance', [ - h('div.request-signature__balance-text', [t('balance')]), + h('div.request-signature__balance-text', [this.context.t('balance')]), h('div.request-signature__balance-value', `${balanceInEther} ETH`), @@ -137,7 +142,7 @@ SignatureRequest.prototype.renderRequestInfo = function () { return h('div.request-signature__request-info', [ h('div.request-signature__headline', [ - t('yourSigRequested'), + this.context.t('yourSigRequested'), ]), ]) @@ -155,18 +160,18 @@ SignatureRequest.prototype.msgHexToText = function (hex) { SignatureRequest.prototype.renderBody = function () { let rows - let notice = t('youSign') + ':' + let notice = this.context.t('youSign') + ':' const { txData } = this.props const { type, msgParams: { data } } = txData if (type === 'personal_sign') { - rows = [{ name: t('message'), value: this.msgHexToText(data) }] + rows = [{ name: this.context.t('message'), value: this.msgHexToText(data) }] } else if (type === 'eth_signTypedData') { rows = data } else if (type === 'eth_sign') { - rows = [{ name: t('message'), value: data }] - notice = t('signNotice') + rows = [{ name: this.context.t('message'), value: data }] + notice = this.context.t('signNotice') } return h('div.request-signature__body', {}, [ @@ -225,10 +230,10 @@ SignatureRequest.prototype.renderFooter = function () { return h('div.request-signature__footer', [ h('button.btn-secondary--lg.request-signature__footer__cancel-button', { onClick: cancel, - }, t('cancel')), + }, this.context.t('cancel')), h('button.btn-primary--lg', { onClick: sign, - }, t('sign')), + }, this.context.t('sign')), ]) } diff --git a/ui/app/components/token-list.js b/ui/app/components/token-list.js index 01529aeda..150a3762d 100644 --- a/ui/app/components/token-list.js +++ b/ui/app/components/token-list.js @@ -1,11 +1,11 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const inherits = require('util').inherits const TokenTracker = require('eth-token-tracker') const TokenCell = require('./token-cell.js') const connect = require('react-redux').connect const selectors = require('../selectors') -const t = require('../../i18n') function mapStateToProps (state) { return { @@ -25,8 +25,13 @@ for (const address in contracts) { } } +TokenList.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps)(TokenList) + inherits(TokenList, Component) function TokenList () { this.state = { @@ -43,7 +48,7 @@ TokenList.prototype.render = function () { const { tokens, isLoading, error } = state if (isLoading) { - return this.message(t('loadingTokens')) + return this.message(this.context.t('loadingTokens')) } if (error) { @@ -53,7 +58,7 @@ TokenList.prototype.render = function () { padding: '80px', }, }, [ - t('troubleTokenBalances'), + this.context.t('troubleTokenBalances'), h('span.hotFix', { style: { color: 'rgba(247, 134, 28, 1)', @@ -64,7 +69,7 @@ TokenList.prototype.render = function () { url: `https://ethplorer.io/address/${userAddress}`, }) }, - }, t('here')), + }, this.context.t('here')), ]) } diff --git a/ui/app/components/tx-list-item.js b/ui/app/components/tx-list-item.js index d104eda88..42c008798 100644 --- a/ui/app/components/tx-list-item.js +++ b/ui/app/components/tx-list-item.js @@ -1,4 +1,5 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const connect = require('react-redux').connect const inherits = require('util').inherits @@ -14,10 +15,14 @@ const { conversionUtil, multiplyCurrencies } = require('../conversion-util') const { calcTokenAmount } = require('../token-util') const { getCurrentCurrency } = require('../selectors') -const t = require('../../i18n') + +TxListItem.contextTypes = { + t: PropTypes.func, +} module.exports = connect(mapStateToProps, mapDispatchToProps)(TxListItem) + function mapStateToProps (state) { return { tokens: state.metamask.tokens, @@ -63,20 +68,24 @@ TxListItem.prototype.getAddressText = function () { const { address, txParams = {}, + isMsg, } = this.props const decodedData = txParams.data && abiDecoder.decodeMethod(txParams.data) const { name: txDataName, params = [] } = decodedData || {} const { value } = params[0] || {} - switch (txDataName) { - case 'transfer': - return `${value.slice(0, 10)}...${value.slice(-4)}` - default: - return address - ? `${address.slice(0, 10)}...${address.slice(-4)}` - : t('contractDeployment') + let addressText + if (txDataName === 'transfer' || address) { + const addressToRender = txDataName === 'transfer' ? value : address + addressText = `${addressToRender.slice(0, 10)}...${addressToRender.slice(-4)}` + } else if (isMsg) { + addressText = this.context.t('sigRequest') + } else { + addressText = this.context.t('contractDeployment') } + + return addressText } TxListItem.prototype.getSendEtherTotal = function () { @@ -186,6 +195,9 @@ TxListItem.prototype.showRetryButton = function () { transactionId, txParams, } = this.props + if (!txParams) { + return false + } const currentNonce = txParams.nonce const currentNonceTxs = selectedAddressTxList.filter(tx => tx.txParams.nonce === currentNonce) const currentNonceSubmittedTxs = currentNonceTxs.filter(tx => tx.status === 'submitted') @@ -307,21 +319,21 @@ TxListItem.prototype.txStatusIndicator = function () { let name if (transactionStatus === 'unapproved') { - name = t('unapproved') + name = this.context.t('unapproved') } else if (transactionStatus === 'rejected') { - name = t('rejected') + name = this.context.t('rejected') } else if (transactionStatus === 'approved') { - name = t('approved') + name = this.context.t('approved') } else if (transactionStatus === 'signed') { - name = t('signed') + name = this.context.t('signed') } else if (transactionStatus === 'submitted') { - name = t('submitted') + name = this.context.t('submitted') } else if (transactionStatus === 'confirmed') { - name = t('confirmed') + name = this.context.t('confirmed') } else if (transactionStatus === 'failed') { - name = t('failed') + name = this.context.t('failed') } else if (transactionStatus === 'dropped') { - name = t('dropped') + name = this.context.t('dropped') } return name } diff --git a/ui/app/components/tx-list.js b/ui/app/components/tx-list.js index 037c7de8c..740c4a4ab 100644 --- a/ui/app/components/tx-list.js +++ b/ui/app/components/tx-list.js @@ -1,4 +1,5 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const connect = require('react-redux').connect const h = require('react-hyperscript') const inherits = require('util').inherits @@ -10,10 +11,14 @@ const { formatDate } = require('../util') const { showConfTxPage } = require('../actions') const classnames = require('classnames') const { tokenInfoGetter } = require('../token-util') -const t = require('../../i18n') + +TxList.contextTypes = { + t: PropTypes.func, +} module.exports = connect(mapStateToProps, mapDispatchToProps)(TxList) + function mapStateToProps (state) { return { txsToRender: selectors.transactionsSelector(state), @@ -40,7 +45,7 @@ TxList.prototype.render = function () { return h('div.flex-column', [ h('div.flex-row.tx-list-header-wrapper', [ h('div.flex-row.tx-list-header', [ - h('div', t('transactions')), + h('div', this.context.t('transactions')), ]), ]), h('div.flex-column.tx-list-container', {}, [ @@ -57,7 +62,7 @@ TxList.prototype.renderTransaction = function () { : [h( 'div.tx-list-item.tx-list-item--empty', { key: 'tx-list-none' }, - [ t('noTransactions') ], + [ this.context.t('noTransactions') ], )] } @@ -72,9 +77,9 @@ TxList.prototype.renderTransactionListItem = function (transaction, conversionRa const props = { dateString: formatDate(transaction.time), - address: transaction.txParams.to, + address: transaction.txParams && transaction.txParams.to, transactionStatus: transaction.status, - transactionAmount: transaction.txParams.value, + transactionAmount: transaction.txParams && transaction.txParams.value, transactionId: transaction.id, transactionHash: transaction.hash, transactionNetworkId: transaction.metamaskNetworkId, @@ -96,6 +101,7 @@ TxList.prototype.renderTransactionListItem = function (transaction, conversionRa const opts = { key: transactionId || transactionHash, txParams: transaction.txParams, + isMsg: Boolean(transaction.msgParams), transactionStatus, transactionId, dateString, @@ -110,8 +116,8 @@ TxList.prototype.renderTransactionListItem = function (transaction, conversionRa const isUnapproved = transactionStatus === 'unapproved' if (isUnapproved) { - opts.onClick = () => showConfTxPage({id: transactionId}) - opts.transactionStatus = t('Not Started') + opts.onClick = () => showConfTxPage({ id: transactionId }) + opts.transactionStatus = this.context.t('notStarted') } else if (transactionHash) { opts.onClick = () => this.view(transactionHash, transactionNetworkId) } diff --git a/ui/app/components/tx-view.js b/ui/app/components/tx-view.js index bf2065106..ca24e813f 100644 --- a/ui/app/components/tx-view.js +++ b/ui/app/components/tx-view.js @@ -1,18 +1,23 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const connect = require('react-redux').connect const h = require('react-hyperscript') const ethUtil = require('ethereumjs-util') const inherits = require('util').inherits const actions = require('../actions') const selectors = require('../selectors') -const t = require('../../i18n') const BalanceComponent = require('./balance-component') const TxList = require('./tx-list') const Identicon = require('./identicon') +TxView.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(TxView) + function mapStateToProps (state) { const sidebarOpen = state.appState.sidebarOpen const isMascara = state.appState.isMascara @@ -73,21 +78,21 @@ TxView.prototype.renderButtons = function () { onClick: () => showModal({ name: 'DEPOSIT_ETHER', }), - }, t('deposit')), + }, this.context.t('deposit')), h('button.btn-primary.hero-balance-button', { style: { marginLeft: '0.8em', }, onClick: showSendPage, - }, t('send')), + }, this.context.t('send')), ]) ) : ( h('div.flex-row.flex-center.hero-balance-buttons', [ h('button.btn-primary.hero-balance-button', { onClick: showSendTokenPage, - }, t('send')), + }, this.context.t('send')), ]) ) } diff --git a/ui/app/components/wallet-view.js b/ui/app/components/wallet-view.js index 2c6d7f784..e6b94ad12 100644 --- a/ui/app/components/wallet-view.js +++ b/ui/app/components/wallet-view.js @@ -1,4 +1,5 @@ const Component = require('react').Component +const PropTypes = require('prop-types') const connect = require('react-redux').connect const h = require('react-hyperscript') const inherits = require('util').inherits @@ -11,10 +12,14 @@ const actions = require('../actions') const BalanceComponent = require('./balance-component') const TokenList = require('./token-list') const selectors = require('../selectors') -const t = require('../../i18n') + +WalletView.contextTypes = { + t: PropTypes.func, +} module.exports = connect(mapStateToProps, mapDispatchToProps)(WalletView) + function mapStateToProps (state) { return { @@ -117,7 +122,7 @@ WalletView.prototype.render = function () { onClick: hideSidebar, }), - h('div.wallet-view__keyring-label.allcaps', isLoose ? t('imported') : ''), + h('div.wallet-view__keyring-label.allcaps', isLoose ? this.context.t('imported') : ''), h('div.flex-column.flex-center.wallet-view__name-container', { style: { margin: '0 auto' }, @@ -134,13 +139,13 @@ WalletView.prototype.render = function () { selectedIdentity.name, ]), - h('button.btn-clear.wallet-view__details-button.allcaps', t('details')), + h('button.btn-clear.wallet-view__details-button.allcaps', this.context.t('details')), ]), ]), h(Tooltip, { position: 'bottom', - title: this.state.hasCopied ? t('copiedExclamation') : t('copyToClipboard'), + title: this.state.hasCopied ? this.context.t('copiedExclamation') : this.context.t('copyToClipboard'), wrapperClassName: 'wallet-view__tooltip', }, [ h('button.wallet-view__address', { @@ -173,7 +178,7 @@ WalletView.prototype.render = function () { showAddTokenPage() hideSidebar() }, - }, t('addToken')), + }, this.context.t('addToken')), ]) } diff --git a/ui/app/css/itcss/components/add-token.scss b/ui/app/css/itcss/components/add-token.scss index f5c1de67c..2fdda6f43 100644 --- a/ui/app/css/itcss/components/add-token.scss +++ b/ui/app/css/itcss/components/add-token.scss @@ -8,6 +8,7 @@ font-family: 'Roboto'; background: white; border-radius: 8px; + box-shadow: 0 0 7px 0 rgba(0, 0, 0, 0.08); &__wrapper { background-color: $white; @@ -20,7 +21,7 @@ &__header { display: flex; flex-flow: column nowrap; - padding: 16px 16px 0px; + padding: 20px 20px 0px; border-bottom: 1px solid $geyser; flex: 0 0 auto; @@ -31,7 +32,8 @@ span { font-family: Roboto; - font-size: 16px; + font-size: 16px; + font-weight: 400; line-height: 21px; margin-left: 8px; } @@ -44,8 +46,13 @@ margin-top: 4px; } + &__subtitle { + font-weight: 400; + margin-top: 15px; + margin-bottom: 21px; + } + &__tabs { - margin-left: 22px; display: flex; &__tab { @@ -54,6 +61,7 @@ color: $dusty-gray; font-family: Roboto; font-size: 18px; + font-weight: 400; line-height: 24px; text-align: center; } @@ -65,6 +73,7 @@ &__unselected:hover { color: $black; border-bottom: none; + cursor: pointer; } &__selected { @@ -76,7 +85,7 @@ &__info-box { height: 96px; - margin: 20px 24px 0px; + margin: 20px 20px 0px; border-radius: 4px; background-color: $alabaster; position: relative; @@ -98,6 +107,7 @@ color: $mid-gray; font-family: Roboto; font-size: 14px; + font-weight: 400; margin-top: 15px; margin-bottom: 9px; } @@ -107,6 +117,7 @@ color: $mid-gray; font-family: Roboto; font-size: 12px; + font-weight: 400; line-height: 18px; } @@ -124,7 +135,8 @@ } &__confirmation-description { - margin: 12px 0; + font-weight: 400; + margin: 20px 0 40px 0; } &__content-container { @@ -151,7 +163,7 @@ &__input, &__add-custom-input { height: 54px; - padding: 21px 6px; + padding: 0px 20px; border: 1px solid $geyser; border-radius: 4px; margin: 22px 24px; @@ -232,6 +244,7 @@ &__add-custom-label { font-size: 16px; + font-weight: 400; line-height: 21px; margin-left: 22px; color: $scorpion; @@ -274,9 +287,11 @@ color: #5B5D67; font-family: Roboto; font-size: 18px; + font-weight: 400; line-height: 24px; margin-left: 24px; margin-top: 8px; + margin-bottom: 20px; } &__token-icons-container { @@ -317,6 +332,7 @@ } &__token-name { + font-weight: 400; font-size: 14px; line-height: 19px; } @@ -368,6 +384,7 @@ &__symbol { color: $scorpion; font-size: 16px; + font-weight: 400; line-height: 24px; } } diff --git a/ui/app/css/itcss/components/confirm.scss b/ui/app/css/itcss/components/confirm.scss index abe138f54..47762e8de 100644 --- a/ui/app/css/itcss/components/confirm.scss +++ b/ui/app/css/itcss/components/confirm.scss @@ -266,6 +266,7 @@ section .confirm-screen-account-number, .confirm-screen-total-box { background-color: $wild-sand; + position: relative; .confirm-screen-label { line-height: 21px; @@ -287,6 +288,41 @@ section .confirm-screen-account-number, } } +.confirm-screen-error { + font-size: 12px; + line-height: 12px; + color: #f00; + position: absolute; + right: 12px; + width: 80px; + text-align: right; +} + +.confirm-screen-row.confirm-screen-total-box { + .confirm-screen-section-column--with-error { + flex: 0.6; + } +} + +@media screen and (max-width: 379px) { + .confirm-screen-row.confirm-screen-total-box { + .confirm-screen-section-column--with-error { + flex: 0.4; + } + } +} + +.confirm-screen-form { + position: relative; + + .confirm-screen-error { + right: 0; + width: 100%; + margin-top: 7px; + text-align: center; + } +} + .confirm-screen-confirm-button { height: 50px; border-radius: 4px; diff --git a/ui/app/css/itcss/components/token-list.scss b/ui/app/css/itcss/components/token-list.scss index 9dc4f1055..e8de317e3 100644 --- a/ui/app/css/itcss/components/token-list.scss +++ b/ui/app/css/itcss/components/token-list.scss @@ -10,9 +10,14 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and ( transition: linear 200ms; background-color: rgba($wallet-balance-bg, 0); position: relative; + flex: 1; + min-width: 0; &__token-balance { font-size: 1.5rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; @media #{$wallet-balance-breakpoint-range} { font-size: 95%; @@ -51,7 +56,8 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and ( &__balance-ellipsis { display: flex; align-items: center; - width: 100%; + min-width: 0; + flex: 1; } &__ellipsis { @@ -61,6 +67,7 @@ $wallet-balance-breakpoint-range: "screen and (min-width: #{$break-large}) and ( &__balance-wrapper { flex: 1 1 auto; + min-width: 0; } } diff --git a/ui/app/css/itcss/settings/typography.scss b/ui/app/css/itcss/settings/typography.scss index 8a56d9c6c..18c444c8a 100644 --- a/ui/app/css/itcss/settings/typography.scss +++ b/ui/app/css/itcss/settings/typography.scss @@ -1,4 +1,4 @@ -@import url('/fonts/Font_Awesome/font-awesome.min.css'); +@import url('./fonts/Font_Awesome/font-awesome.min.css'); @font-face { font-family: 'Roboto'; @@ -338,8 +338,8 @@ @font-face { font-family: 'Montserrat Regular'; - src: url('/fonts/Montserrat/Montserrat-Regular.woff') format('woff'); - src: url('/fonts/Montserrat/Montserrat-Regular.ttf') format('truetype'); + src: url('./fonts/Montserrat/Montserrat-Regular.woff') format('woff'); + src: url('./fonts/Montserrat/Montserrat-Regular.ttf') format('truetype'); font-weight: 400; font-style: normal; font-size: 'small'; @@ -347,59 +347,59 @@ @font-face { font-family: 'Montserrat Bold'; - src: url('/fonts/Montserrat/Montserrat-Bold.woff') format('woff'); - src: url('/fonts/Montserrat/Montserrat-Bold.ttf') format('truetype'); + src: url('./fonts/Montserrat/Montserrat-Bold.woff') format('woff'); + src: url('./fonts/Montserrat/Montserrat-Bold.ttf') format('truetype'); font-weight: 400; font-style: normal; } @font-face { font-family: 'Montserrat Light'; - src: url('/fonts/Montserrat/Montserrat-Light.woff') format('woff'); - src: url('/fonts/Montserrat/Montserrat-Light.ttf') format('truetype'); + src: url('./fonts/Montserrat/Montserrat-Light.woff') format('woff'); + src: url('./fonts/Montserrat/Montserrat-Light.ttf') format('truetype'); font-weight: 400; font-style: normal; } @font-face { font-family: 'Montserrat UltraLight'; - src: url('/fonts/Montserrat/Montserrat-UltraLight.woff') format('woff'); - src: url('/fonts/Montserrat/Montserrat-UltraLight.ttf') format('truetype'); + src: url('./fonts/Montserrat/Montserrat-UltraLight.woff') format('woff'); + src: url('./fonts/Montserrat/Montserrat-UltraLight.ttf') format('truetype'); font-weight: 400; font-style: normal; } @font-face { font-family: 'DIN OT'; - src: url('/fonts/DIN_OT/DINOT-2.otf') format('opentype'); + src: url('./fonts/DIN_OT/DINOT-2.otf') format('opentype'); font-weight: 400; font-style: normal; } @font-face { font-family: 'DIN OT Light'; - src: url('/fonts/DIN_OT/DINOT-2.otf') format('opentype'); + src: url('./fonts/DIN_OT/DINOT-2.otf') format('opentype'); font-weight: 200; font-style: normal; } @font-face { font-family: 'DIN NEXT'; - src: url('/fonts/DIN Next/DIN Next W01 Regular.otf') format('opentype'); + src: url('./fonts/DIN Next/DIN Next W01 Regular.otf') format('opentype'); font-weight: 400; font-style: normal; } @font-face { font-family: 'DIN NEXT Light'; - src: url('/fonts/DIN Next/DIN Next W10 Light.otf') format('opentype'); + src: url('./fonts/DIN Next/DIN Next W10 Light.otf') format('opentype'); font-weight: 400; font-style: normal; } @font-face { font-family: 'Lato'; - src: url('/fonts/Lato/Lato-Regular.ttf') format('truetype'); + src: url('./fonts/Lato/Lato-Regular.ttf') format('truetype'); font-weight: 400; font-style: normal; } diff --git a/ui/app/first-time/init-menu.js b/ui/app/first-time/init-menu.js index 370fdd5b7..4ab5f06c0 100644 --- a/ui/app/first-time/init-menu.js +++ b/ui/app/first-time/init-menu.js @@ -1,20 +1,25 @@ const inherits = require('util').inherits const EventEmitter = require('events').EventEmitter const Component = require('react').Component +const PropTypes = require('prop-types') const connect = require('react-redux').connect const h = require('react-hyperscript') const Mascot = require('../components/mascot') const actions = require('../actions') const Tooltip = require('../components/tooltip') -const t = require('../../i18n') const getCaretCoordinates = require('textarea-caret') const environmentType = require('../../../app/scripts/lib/environment-type') const { OLD_UI_NETWORK_TYPE } = require('../../../app/scripts/config').enums let isSubmitting = false +InitializeMenuScreen.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps)(InitializeMenuScreen) + inherits(InitializeMenuScreen, Component) function InitializeMenuScreen () { Component.call(this) @@ -60,7 +65,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { color: '#7F8082', marginBottom: 10, }, - }, t('appName')), + }, this.context.t('appName')), h('div', [ @@ -70,10 +75,10 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { color: '#7F8082', display: 'inline', }, - }, t('encryptNewDen')), + }, this.context.t('encryptNewDen')), h(Tooltip, { - title: t('denExplainer'), + title: this.context.t('denExplainer'), }, [ h('i.fa.fa-question-circle.pointer', { style: { @@ -93,7 +98,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { h('input.large-input.letter-spacey', { type: 'password', id: 'password-box', - placeholder: t('newPassword'), + placeholder: this.context.t('newPassword'), onInput: this.inputChanged.bind(this), style: { width: 260, @@ -105,7 +110,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { h('input.large-input.letter-spacey', { type: 'password', id: 'password-box-confirm', - placeholder: t('confirmPassword'), + placeholder: this.context.t('confirmPassword'), onKeyPress: this.createVaultOnEnter.bind(this), onInput: this.inputChanged.bind(this), style: { @@ -120,7 +125,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { style: { margin: 12, }, - }, t('createDen')), + }, this.context.t('createDen')), h('.flex-row.flex-center.flex-grow', [ h('p.pointer', { @@ -130,7 +135,7 @@ InitializeMenuScreen.prototype.renderMenu = function (state) { color: 'rgb(247, 134, 28)', textDecoration: 'underline', }, - }, t('importDen')), + }, this.context.t('importDen')), ]), h('.flex-row.flex-center.flex-grow', [ @@ -179,12 +184,12 @@ InitializeMenuScreen.prototype.createNewVaultAndKeychain = function () { var passwordConfirm = passwordConfirmBox.value if (password.length < 8) { - this.warning = t('passwordShort') + this.warning = this.context.t('passwordShort') this.props.dispatch(actions.displayWarning(this.warning)) return } if (password !== passwordConfirm) { - this.warning = t('passwordMismatch') + this.warning = this.context.t('passwordMismatch') this.props.dispatch(actions.displayWarning(this.warning)) return } diff --git a/ui/app/i18n-provider.js b/ui/app/i18n-provider.js new file mode 100644 index 000000000..fe6d62c67 --- /dev/null +++ b/ui/app/i18n-provider.js @@ -0,0 +1,36 @@ +const { Component } = require('react') +const connect = require('react-redux').connect +const PropTypes = require('prop-types') +const t = require('../i18n-helper').getMessage + +class I18nProvider extends Component { + getChildContext() { + const { localeMessages } = this.props + return { + t: t.bind(null, localeMessages), + } + } + + render() { + return this.props.children + } +} + +I18nProvider.propTypes = { + localeMessages: PropTypes.object, + children: PropTypes.object, +} + +I18nProvider.childContextTypes = { + t: PropTypes.func, +} + +const mapStateToProps = state => { + const { localeMessages } = state + return { + localeMessages, + } +} + +module.exports = connect(mapStateToProps)(I18nProvider) + diff --git a/ui/app/keychains/hd/recover-seed/confirmation.js b/ui/app/keychains/hd/recover-seed/confirmation.js index bc5339549..02183f096 100644 --- a/ui/app/keychains/hd/recover-seed/confirmation.js +++ b/ui/app/keychains/hd/recover-seed/confirmation.js @@ -1,13 +1,17 @@ const inherits = require('util').inherits - const Component = require('react').Component +const PropTypes = require('prop-types') const connect = require('react-redux').connect const h = require('react-hyperscript') const actions = require('../../../actions') -const t = require('../../../../i18n') + +RevealSeedConfirmation.contextTypes = { + t: PropTypes.func, +} module.exports = connect(mapStateToProps)(RevealSeedConfirmation) + inherits(RevealSeedConfirmation, Component) function RevealSeedConfirmation () { Component.call(this) @@ -50,13 +54,13 @@ RevealSeedConfirmation.prototype.render = function () { }, }, [ - h('h4', t('revealSeedWordsWarning')), + h('h4', this.context.t('revealSeedWordsWarning')), // confirmation h('input.large-input.letter-spacey', { type: 'password', id: 'password-box', - placeholder: t('enterPasswordConfirm'), + placeholder: this.context.t('enterPasswordConfirm'), onKeyPress: this.checkConfirmation.bind(this), style: { width: 260, @@ -92,7 +96,7 @@ RevealSeedConfirmation.prototype.render = function () { ), props.inProgress && ( - h('span.in-progress-notification', t('generatingSeed')) + h('span.in-progress-notification', this.context.t('generatingSeed')) ), ]), ]) diff --git a/ui/app/keychains/hd/restore-vault.js b/ui/app/keychains/hd/restore-vault.js index 5e4e004cf..38ad14adb 100644 --- a/ui/app/keychains/hd/restore-vault.js +++ b/ui/app/keychains/hd/restore-vault.js @@ -1,12 +1,17 @@ const inherits = require('util').inherits +const PropTypes = require('prop-types') const PersistentForm = require('../../../lib/persistent-form') const connect = require('react-redux').connect const h = require('react-hyperscript') -const t = require('../../../i18n') const actions = require('../../actions') +RestoreVaultScreen.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps)(RestoreVaultScreen) + inherits(RestoreVaultScreen, PersistentForm) function RestoreVaultScreen () { PersistentForm.call(this) @@ -37,23 +42,23 @@ RestoreVaultScreen.prototype.render = function () { padding: 6, }, }, [ - t('restoreVault'), + this.context.t('restoreVault'), ]), // wallet seed entry - h('h3', t('walletSeed')), + h('h3', this.context.t('walletSeed')), h('textarea.twelve-word-phrase.letter-spacey', { dataset: { persistentFormId: 'wallet-seed', }, - placeholder: t('secretPhrase'), + placeholder: this.context.t('secretPhrase'), }), // password h('input.large-input.letter-spacey', { type: 'password', id: 'password-box', - placeholder: t('newPassword8Chars'), + placeholder: this.context.t('newPassword8Chars'), dataset: { persistentFormId: 'password', }, @@ -67,7 +72,7 @@ RestoreVaultScreen.prototype.render = function () { h('input.large-input.letter-spacey', { type: 'password', id: 'password-box-confirm', - placeholder: t('confirmPassword'), + placeholder: this.context.t('confirmPassword'), onKeyPress: this.createOnEnter.bind(this), dataset: { persistentFormId: 'password-confirmation', @@ -97,7 +102,7 @@ RestoreVaultScreen.prototype.render = function () { style: { textTransform: 'uppercase', }, - }, t('cancel')), + }, this.context.t('cancel')), // submit h('button.primary', { @@ -105,7 +110,7 @@ RestoreVaultScreen.prototype.render = function () { style: { textTransform: 'uppercase', }, - }, t('ok')), + }, this.context.t('ok')), ]), ]) ) @@ -136,13 +141,13 @@ RestoreVaultScreen.prototype.createNewVaultAndRestore = function () { var passwordConfirmBox = document.getElementById('password-box-confirm') var passwordConfirm = passwordConfirmBox.value if (password.length < 8) { - this.warning = t('passwordNotLongEnough') + this.warning = this.context.t('passwordNotLongEnough') this.props.dispatch(actions.displayWarning(this.warning)) return } if (password !== passwordConfirm) { - this.warning = t('passwordsDontMatch') + this.warning = this.context.t('passwordsDontMatch') this.props.dispatch(actions.displayWarning(this.warning)) return } @@ -152,18 +157,18 @@ RestoreVaultScreen.prototype.createNewVaultAndRestore = function () { // true if the string has more than a space between words. if (seed.split(' ').length > 1) { - this.warning = t('spaceBetween') + this.warning = this.context.t('spaceBetween') this.props.dispatch(actions.displayWarning(this.warning)) return } // true if seed contains a character that is not between a-z or a space if (!seed.match(/^[a-z ]+$/)) { - this.warning = t('loweCaseWords') + this.warning = this.context.t('loweCaseWords') this.props.dispatch(actions.displayWarning(this.warning)) return } if (seed.split(' ').length !== 12) { - this.warning = t('seedPhraseReq') + this.warning = this.context.t('seedPhraseReq') this.props.dispatch(actions.displayWarning(this.warning)) return } diff --git a/ui/app/metamask-connect.js b/ui/app/metamask-connect.js new file mode 100644 index 000000000..8da594635 --- /dev/null +++ b/ui/app/metamask-connect.js @@ -0,0 +1,27 @@ +const connect = require('react-redux').connect +const t = require('../i18n-helper').getMessage + +const metamaskConnect = (mapStateToProps, mapDispatchToProps) => { + return connect( + _higherOrderMapStateToProps(mapStateToProps), + mapDispatchToProps + ) +} + +const _higherOrderMapStateToProps = (mapStateToProps) => { + let _t + let currentLocale + return (state, ownProps = {}) => { + const stateProps = mapStateToProps + ? mapStateToProps(state, ownProps) + : ownProps + if (currentLocale !== state.metamask.currentLocale) { + currentLocale = state.metamask.currentLocale + _t = t.bind(null, state.localeMessages) + } + stateProps.t = _t + return stateProps + } +} + +module.exports = metamaskConnect
\ No newline at end of file diff --git a/ui/app/reducers.js b/ui/app/reducers.js index 70b7e71dc..f155b2bf3 100644 --- a/ui/app/reducers.js +++ b/ui/app/reducers.js @@ -7,6 +7,7 @@ const copyToClipboard = require('copy-to-clipboard') const reduceIdentities = require('./reducers/identities') const reduceMetamask = require('./reducers/metamask') const reduceApp = require('./reducers/app') +const reduceLocale = require('./reducers/locale') window.METAMASK_CACHED_LOG_STATE = null @@ -38,6 +39,12 @@ function rootReducer (state, action) { state.appState = reduceApp(state, action) + // + // LocaleMessages + // + + state.localeMessages = reduceLocale(state, action) + window.METAMASK_CACHED_LOG_STATE = state return state } diff --git a/ui/app/reducers/locale.js b/ui/app/reducers/locale.js new file mode 100644 index 000000000..bdd97acb4 --- /dev/null +++ b/ui/app/reducers/locale.js @@ -0,0 +1,17 @@ +const extend = require('xtend') +const actions = require('../actions') + +module.exports = reduceMetamask + +function reduceMetamask (state, action) { + const localeMessagesState = extend({}, state.localeMessages) + + switch (action.type) { + case actions.SET_LOCALE_MESSAGES: + return extend(localeMessagesState, { + current: action.value, + }) + default: + return localeMessagesState + } +} diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js index 9cba5e83b..6d0a5bb10 100644 --- a/ui/app/reducers/metamask.js +++ b/ui/app/reducers/metamask.js @@ -47,6 +47,7 @@ function reduceMetamask (state, action) { networkEndpointType: OLD_UI_NETWORK_TYPE, isRevealingSeedWords: false, welcomeScreenSeen: false, + currentLocale: '', }, state.metamask) switch (action.type) { @@ -357,6 +358,11 @@ function reduceMetamask (state, action) { welcomeScreenSeen: true, }) + case action.SET_CURRENT_LOCALE: + return extend(metamaskState, { + currentLocale: action.value, + }) + default: return metamaskState diff --git a/ui/app/select-app.js b/ui/app/select-app.js index 193c98353..101eb1cf6 100644 --- a/ui/app/select-app.js +++ b/ui/app/select-app.js @@ -7,6 +7,7 @@ const OldApp = require('../../old-ui/app/app') const { autoAddToBetaUI } = require('./selectors') const { setFeatureFlag, setNetworkEndpoints } = require('./actions') const { BETA_UI_NETWORK_TYPE } = require('../../app/scripts/config').enums +const I18nProvider = require('./i18n-provider') function mapStateToProps (state) { return { @@ -62,7 +63,7 @@ SelectedApp.prototype.render = function () { // const Selected = betaUI || isMascara || firstTime ? App : OldApp const { betaUI, isMascara } = this.props - const Selected = betaUI || isMascara ? App : OldApp + const Selected = betaUI || isMascara ? h(I18nProvider, [ h(App) ]) : h(OldApp) - return h(Selected) + return Selected } diff --git a/ui/app/send-v2.js b/ui/app/send-v2.js index 620da73f8..0f2997fb2 100644 --- a/ui/app/send-v2.js +++ b/ui/app/send-v2.js @@ -1,7 +1,7 @@ const { inherits } = require('util') +const PropTypes = require('prop-types') const PersistentForm = require('../lib/persistent-form') const h = require('react-hyperscript') -const t = require('../i18n') const ethAbi = require('ethereumjs-abi') const ethUtil = require('ethereumjs-util') @@ -27,9 +27,14 @@ const { const { isBalanceSufficient, isTokenBalanceSufficient, + getGasTotal, } = require('./components/send/send-utils') const { isValidAddress } = require('./util') +SendTransactionScreen.contextTypes = { + t: PropTypes.func, +} + module.exports = SendTransactionScreen inherits(SendTransactionScreen, PersistentForm) @@ -128,7 +133,7 @@ SendTransactionScreen.prototype.updateGas = function () { estimateGas(estimateGasParams), ]) .then(([gasPrice, gas]) => { - const newGasTotal = this.getGasTotal(gas, gasPrice) + const newGasTotal = getGasTotal(gas, gasPrice) updateGasTotal(newGasTotal) this.setState({ gasLoadingError: false }) }) @@ -136,19 +141,11 @@ SendTransactionScreen.prototype.updateGas = function () { this.setState({ gasLoadingError: true }) }) } else { - const newGasTotal = this.getGasTotal(gasLimit, gasPrice) + const newGasTotal = getGasTotal(gasLimit, gasPrice) updateGasTotal(newGasTotal) } } -SendTransactionScreen.prototype.getGasTotal = function (gasLimit, gasPrice) { - return multiplyCurrencies(gasLimit, gasPrice, { - toNumericBase: 'hex', - multiplicandBase: 16, - multiplierBase: 16, - }) -} - SendTransactionScreen.prototype.componentDidUpdate = function (prevProps) { const { from: { balance }, @@ -189,9 +186,9 @@ SendTransactionScreen.prototype.renderHeader = function () { return h('div.page-container__header', [ - h('div.page-container__title', selectedToken ? t('sendTokens') : t('sendETH')), + h('div.page-container__title', selectedToken ? this.context.t('sendTokens') : this.context.t('sendETH')), - h('div.page-container__subtitle', t('onlySendToEtherAddress')), + h('div.page-container__subtitle', this.context.t('onlySendToEtherAddress')), h('div.page-container__header-close', { onClick: () => { @@ -262,11 +259,11 @@ SendTransactionScreen.prototype.handleToChange = function (to, nickname = '') { let toError = null if (!to) { - toError = t('required') + toError = this.context.t('required') } else if (!isValidAddress(to)) { - toError = t('invalidAddressRecipient') + toError = this.context.t('invalidAddressRecipient') } else if (to === from) { - toError = t('fromToSame') + toError = this.context.t('fromToSame') } updateSendTo(to, nickname) @@ -282,9 +279,9 @@ SendTransactionScreen.prototype.renderToRow = function () { h('div.send-v2__form-label', [ - t('to'), + this.context.t('to'), - this.renderErrorMessage(t('to')), + this.renderErrorMessage(this.context.t('to')), ]), @@ -385,11 +382,11 @@ SendTransactionScreen.prototype.validateAmount = function (value) { ) if (conversionRate && !sufficientBalance) { - amountError = t('insufficientFunds') + amountError = this.context.t('insufficientFunds') } else if (verifyTokenBalance && !sufficientTokens) { - amountError = t('insufficientTokens') + amountError = this.context.t('insufficientTokens') } else if (amountLessThanZero) { - amountError = t('negativeETH') + amountError = this.context.t('negativeETH') } updateSendErrors({ amount: amountError }) @@ -419,7 +416,7 @@ SendTransactionScreen.prototype.renderAmountRow = function () { setMaxModeTo(true) this.setAmountToMax() }, - }, [ !maxModeOn ? t('max') : '' ]), + }, [ !maxModeOn ? this.context.t('max') : '' ]), ]), h('div.send-v2__form-field', [ @@ -448,7 +445,7 @@ SendTransactionScreen.prototype.renderGasRow = function () { return h('div.send-v2__form-row', [ - h('div.send-v2__form-label', h('gasFee')), + h('div.send-v2__form-label', this.context.t('gasFee')), h('div.send-v2__form-field', [ @@ -518,11 +515,11 @@ SendTransactionScreen.prototype.renderFooter = function () { clearSend() goHome() }, - }, t('cancel')), + }, this.context.t('cancel')), h('button.btn-primary--lg.page-container__footer-button', { disabled: !noErrors || !gasTotal || missingTokenBalance, onClick: event => this.onSubmit(event), - }, t('next')), + }, this.context.t('next')), ]) } @@ -597,7 +594,7 @@ SendTransactionScreen.prototype.onSubmit = function (event) { event.preventDefault() const { from: {address: from}, - to, + to: _to, amount, gasLimit: gas, gasPrice, @@ -616,6 +613,8 @@ SendTransactionScreen.prototype.onSubmit = function (event) { return } + const to = ethUtil.addHexPrefix(_to) + this.addToAddressBookIfNew(to, toNickname) if (editingTransactionId) { @@ -636,6 +635,10 @@ SendTransactionScreen.prototype.onSubmit = function (event) { txParams.to = to } + Object.keys(txParams).forEach(key => { + txParams[key] = ethUtil.addHexPrefix(txParams[key]) + }) + selectedToken ? signTokenTx(selectedToken.address, to, amount, txParams) : signTx(txParams) diff --git a/ui/app/settings.js b/ui/app/settings.js index 78ca6c94b..3aa7b9c6b 100644 --- a/ui/app/settings.js +++ b/ui/app/settings.js @@ -1,7 +1,7 @@ const { Component } = require('react') const PropTypes = require('prop-types') const h = require('react-hyperscript') -const { connect } = require('react-redux') +const connect = require('react-redux').connect const actions = require('./actions') const infuraCurrencies = require('./infura-conversion.json') const validUrl = require('valid-url') @@ -9,8 +9,8 @@ const { exportAsFile } = require('./util') const TabBar = require('./components/tab-bar') const SimpleDropdown = require('./components/dropdowns/simple-dropdown') const ToggleButton = require('react-toggle-button') +const locales = require('../../app/_locales/index.json') const { OLD_UI_NETWORK_TYPE } = require('../../app/scripts/config').enums -const t = require('../i18n') const getInfuraCurrencyOptions = () => { const sortedCurrencies = infuraCurrencies.objects.sort((a, b) => { @@ -26,6 +26,16 @@ const getInfuraCurrencyOptions = () => { }) } +const getLocaleOptions = () => { + return locales.map((locale) => { + return { + displayValue: `${locale.name}`, + key: locale.code, + value: locale.code, + } + }) +} + class Settings extends Component { constructor (props) { super(props) @@ -45,8 +55,8 @@ class Settings extends Component { return h('div.settings__tabs', [ h(TabBar, { tabs: [ - { content: t('settings'), key: 'settings' }, - { content: t('info'), key: 'info' }, + { content: this.context.t('settings'), key: 'settings' }, + { content: this.context.t('info'), key: 'info' }, ], defaultTab: activeTab, tabSelected: key => this.setState({ activeTab: key }), @@ -59,7 +69,7 @@ class Settings extends Component { return h('div.settings__content-row', [ h('div.settings__content-item', [ - h('span', t('blockiesIdenticon')), + h('span', this.context.t('blockiesIdenticon')), ]), h('div.settings__content-item', [ h('div.settings__content-item-col', [ @@ -79,13 +89,13 @@ class Settings extends Component { return h('div.settings__content-row', [ h('div.settings__content-item', [ - h('span', t('currentConversion')), + h('span', this.context.t('currentConversion')), h('span.settings__content-description', `Updated ${Date(conversionDate)}`), ]), h('div.settings__content-item', [ h('div.settings__content-item-col', [ h(SimpleDropdown, { - placeholder: t('selectCurrency'), + placeholder: this.context.t('selectCurrency'), options: getInfuraCurrencyOptions(), selectedOption: currentCurrency, onSelect: newCurrency => setCurrentCurrency(newCurrency), @@ -95,6 +105,31 @@ class Settings extends Component { ]) } + renderCurrentLocale () { + const { updateCurrentLocale, currentLocale } = this.props + const currentLocaleMeta = locales.find(locale => locale.code === currentLocale) + const currentLocaleName = currentLocaleMeta ? currentLocaleMeta.name : '' + + return h('div.settings__content-row', [ + h('div.settings__content-item', [ + h('span', 'Current Language'), + h('span.settings__content-description', `${currentLocaleName}`), + ]), + h('div.settings__content-item', [ + h('div.settings__content-item-col', [ + h(SimpleDropdown, { + placeholder: 'Select Locale', + options: getLocaleOptions(), + selectedOption: currentLocale, + onSelect: async (newLocale) => { + updateCurrentLocale(newLocale) + }, + }), + ]), + ]), + ]) + } + renderCurrentProvider () { const { metamask: { provider = {} } } = this.props let title, value, color @@ -102,31 +137,31 @@ class Settings extends Component { switch (provider.type) { case 'mainnet': - title = t('currentNetwork') - value = t('mainnet') + title = this.context.t('currentNetwork') + value = this.context.t('mainnet') color = '#038789' break case 'ropsten': - title = t('currentNetwork') - value = t('ropsten') + title = this.context.t('currentNetwork') + value = this.context.t('ropsten') color = '#e91550' break case 'kovan': - title = t('currentNetwork') - value = t('kovan') + title = this.context.t('currentNetwork') + value = this.context.t('kovan') color = '#690496' break case 'rinkeby': - title = t('currentNetwork') - value = t('rinkeby') + title = this.context.t('currentNetwork') + value = this.context.t('rinkeby') color = '#ebb33f' break default: - title = t('currentRpc') + title = this.context.t('currentRpc') value = provider.rpcTarget } @@ -147,12 +182,12 @@ class Settings extends Component { return ( h('div.settings__content-row', [ h('div.settings__content-item', [ - h('span', t('newRPC')), + h('span', this.context.t('newRPC')), ]), h('div.settings__content-item', [ h('div.settings__content-item-col', [ h('input.settings__input', { - placeholder: t('newRPC'), + placeholder: this.context.t('newRPC'), onChange: event => this.setState({ newRpc: event.target.value }), onKeyPress: event => { if (event.key === 'Enter') { @@ -165,7 +200,7 @@ class Settings extends Component { event.preventDefault() this.validateRpc(this.state.newRpc) }, - }, t('save')), + }, this.context.t('save')), ]), ]), ]) @@ -181,9 +216,9 @@ class Settings extends Component { const appendedRpc = `http://${newRpc}` if (validUrl.isWebUri(appendedRpc)) { - displayWarning(t('uriErrorMsg')) + displayWarning(this.context.t('uriErrorMsg')) } else { - displayWarning(t('invalidRPC')) + displayWarning(this.context.t('invalidRPC')) } } } @@ -192,10 +227,10 @@ class Settings extends Component { return ( h('div.settings__content-row', [ h('div.settings__content-item', [ - h('div', t('stateLogs')), + h('div', this.context.t('stateLogs')), h( 'div.settings__content-description', - t('stateLogsDescription') + this.context.t('stateLogsDescription') ), ]), h('div.settings__content-item', [ @@ -204,13 +239,13 @@ class Settings extends Component { onClick (event) { window.logStateString((err, result) => { if (err) { - this.state.dispatch(actions.displayWarning(t('stateLogError'))) + this.state.dispatch(actions.displayWarning(this.context.t('stateLogError'))) } else { exportAsFile('MetaMask State Logs.json', result) } }) }, - }, t('downloadStateLogs')), + }, this.context.t('downloadStateLogs')), ]), ]), ]) @@ -222,7 +257,7 @@ class Settings extends Component { return ( h('div.settings__content-row', [ - h('div.settings__content-item', t('revealSeedWords')), + h('div.settings__content-item', this.context.t('revealSeedWords')), h('div.settings__content-item', [ h('div.settings__content-item-col', [ h('button.btn-primary--lg.settings__button--red', { @@ -230,7 +265,7 @@ class Settings extends Component { event.preventDefault() revealSeedConfirmation() }, - }, t('revealSeedWords')), + }, this.context.t('revealSeedWords')), ]), ]), ]) @@ -242,7 +277,7 @@ class Settings extends Component { return ( h('div.settings__content-row', [ - h('div.settings__content-item', t('useOldUI')), + h('div.settings__content-item', this.context.t('useOldUI')), h('div.settings__content-item', [ h('div.settings__content-item-col', [ h('button.btn-primary--lg.settings__button--orange', { @@ -250,7 +285,7 @@ class Settings extends Component { event.preventDefault() setFeatureFlagToBeta() }, - }, t('useOldUI')), + }, this.context.t('useOldUI')), ]), ]), ]) @@ -261,7 +296,7 @@ class Settings extends Component { const { showResetAccountConfirmationModal } = this.props return h('div.settings__content-row', [ - h('div.settings__content-item', t('resetAccount')), + h('div.settings__content-item', this.context.t('resetAccount')), h('div.settings__content-item', [ h('div.settings__content-item-col', [ h('button.btn-primary--lg.settings__button--orange', { @@ -269,7 +304,7 @@ class Settings extends Component { event.preventDefault() showResetAccountConfirmationModal() }, - }, t('resetAccount')), + }, this.context.t('resetAccount')), ]), ]), ]) @@ -282,6 +317,7 @@ class Settings extends Component { h('div.settings__content', [ warning && h('div.settings__error', warning), this.renderCurrentConversion(), + this.renderCurrentLocale(), // this.renderCurrentProvider(), this.renderNewRpcUrl(), this.renderStateLogs(), @@ -304,13 +340,13 @@ class Settings extends Component { renderInfoLinks () { return ( h('div.settings__content-item.settings__content-item--without-height', [ - h('div.settings__info-link-header', t('links')), + h('div.settings__info-link-header', this.context.t('links')), h('div.settings__info-link-item', [ h('a', { href: 'https://metamask.io/privacy.html', target: '_blank', }, [ - h('span.settings__info-link', t('privacyMsg')), + h('span.settings__info-link', this.context.t('privacyMsg')), ]), ]), h('div.settings__info-link-item', [ @@ -318,7 +354,7 @@ class Settings extends Component { href: 'https://metamask.io/terms.html', target: '_blank', }, [ - h('span.settings__info-link', t('terms')), + h('span.settings__info-link', this.context.t('terms')), ]), ]), h('div.settings__info-link-item', [ @@ -326,7 +362,7 @@ class Settings extends Component { href: 'https://metamask.io/attributions.html', target: '_blank', }, [ - h('span.settings__info-link', t('attributions')), + h('span.settings__info-link', this.context.t('attributions')), ]), ]), h('hr.settings__info-separator'), @@ -335,7 +371,7 @@ class Settings extends Component { href: 'https://support.metamask.io', target: '_blank', }, [ - h('span.settings__info-link', t('supportCenter')), + h('span.settings__info-link', this.context.t('supportCenter')), ]), ]), h('div.settings__info-link-item', [ @@ -343,7 +379,7 @@ class Settings extends Component { href: 'https://metamask.io/', target: '_blank', }, [ - h('span.settings__info-link', t('visitWebSite')), + h('span.settings__info-link', this.context.t('visitWebSite')), ]), ]), h('div.settings__info-link-item', [ @@ -351,7 +387,7 @@ class Settings extends Component { target: '_blank', href: 'mailto:help@metamask.io?subject=Feedback', }, [ - h('span.settings__info-link', t('emailUs')), + h('span.settings__info-link', this.context.t('emailUs')), ]), ]), ]) @@ -373,7 +409,7 @@ class Settings extends Component { h('div.settings__info-item', [ h( 'div.settings__info-about', - t('builtInCalifornia') + this.context.t('builtInCalifornia') ), ]), ]), @@ -417,6 +453,9 @@ Settings.propTypes = { warning: PropTypes.string, goHome: PropTypes.func, isMascara: PropTypes.bool, + updateCurrentLocale: PropTypes.func, + currentLocale: PropTypes.string, + t: PropTypes.func, } const mapStateToProps = state => { @@ -424,6 +463,7 @@ const mapStateToProps = state => { metamask: state.metamask, warning: state.appState.warning, isMascara: state.metamask.isMascara, + currentLocale: state.metamask.currentLocale, } } @@ -435,6 +475,7 @@ const mapDispatchToProps = dispatch => { displayWarning: warning => dispatch(actions.displayWarning(warning)), revealSeedConfirmation: () => dispatch(actions.revealSeedConfirmation()), setUseBlockie: value => dispatch(actions.setUseBlockie(value)), + updateCurrentLocale: key => dispatch(actions.updateCurrentLocale(key)), setFeatureFlagToBeta: () => { return dispatch(actions.setFeatureFlag('betaUI', false, 'OLD_UI_NOTIFICATION_MODAL')) .then(() => dispatch(actions.setNetworkEndpoints(OLD_UI_NETWORK_TYPE))) @@ -445,5 +486,9 @@ const mapDispatchToProps = dispatch => { } } +Settings.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps, mapDispatchToProps)(Settings) diff --git a/ui/app/store.js b/ui/app/store.js index 3bafdee11..feebbabc0 100644 --- a/ui/app/store.js +++ b/ui/app/store.js @@ -4,7 +4,7 @@ const thunkMiddleware = require('redux-thunk').default const rootReducer = require('./reducers') const createLogger = require('redux-logger').createLogger -global.METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' +global.METAMASK_DEBUG = process.env.METAMASK_DEBUG module.exports = configureStore diff --git a/ui/app/unlock.js b/ui/app/unlock.js index 322808619..84d8b7e7c 100644 --- a/ui/app/unlock.js +++ b/ui/app/unlock.js @@ -1,18 +1,23 @@ const inherits = require('util').inherits const Component = require('react').Component +const PropTypes = require('prop-types') const h = require('react-hyperscript') const connect = require('react-redux').connect const actions = require('./actions') const getCaretCoordinates = require('textarea-caret') const EventEmitter = require('events').EventEmitter -const t = require('../i18n') const { OLD_UI_NETWORK_TYPE } = require('../../app/scripts/config').enums const environmentType = require('../../app/scripts/lib/environment-type') const Mascot = require('./components/mascot') +UnlockScreen.contextTypes = { + t: PropTypes.func, +} + module.exports = connect(mapStateToProps)(UnlockScreen) + inherits(UnlockScreen, Component) function UnlockScreen () { Component.call(this) @@ -41,7 +46,7 @@ UnlockScreen.prototype.render = function () { textTransform: 'uppercase', color: '#7F8082', }, - }, t('appName')), + }, this.context.t('appName')), h('input.large-input', { type: 'password', @@ -67,7 +72,7 @@ UnlockScreen.prototype.render = function () { style: { margin: 10, }, - }, t('login')), + }, this.context.t('login')), h('p.pointer', { onClick: () => { @@ -81,7 +86,7 @@ UnlockScreen.prototype.render = function () { color: 'rgb(247, 134, 28)', textDecoration: 'underline', }, - }, t('restoreFromSeed')), + }, this.context.t('restoreFromSeed')), h('p.pointer', { onClick: () => { @@ -94,7 +99,7 @@ UnlockScreen.prototype.render = function () { textDecoration: 'underline', marginTop: '32px', }, - }, t('classicInterface')), + }, this.context.t('classicInterface')), ]) ) } diff --git a/ui/i18n-helper.js b/ui/i18n-helper.js new file mode 100644 index 000000000..3eee55ae9 --- /dev/null +++ b/ui/i18n-helper.js @@ -0,0 +1,42 @@ +// cross-browser connection to extension i18n API +const log = require('loglevel') + +const getMessage = (locale, key, substitutions) => { + // check locale is loaded + if (!locale) { + // throw new Error('Translator - has not loaded a locale yet.') + return '' + } + // check entry is present + const { current, en } = locale + const entry = current[key] || en[key] + if (!entry) { + log.error(`Translator - Unable to find value for "${key}"`) + // throw new Error(`Translator - Unable to find value for "${key}"`) + } + let phrase = entry.message + // perform substitutions + if (substitutions && substitutions.length) { + phrase = phrase.replace(/\$1/g, substitutions[0]) + if (substitutions.length > 1) { + phrase = phrase.replace(/\$2/g, substitutions[1]) + } + } + return phrase +} + +async function fetchLocale (localeName) { + try { + const response = await fetch(`./_locales/${localeName}/messages.json`) + const locale = await response.json() + return locale + } catch (error) { + log.error(`failed to fetch ${localeName} locale because of ${error}`) + return {} + } +} + +module.exports = { + getMessage, + fetchLocale, +} diff --git a/ui/i18n.js b/ui/i18n.js deleted file mode 100644 index abfece426..000000000 --- a/ui/i18n.js +++ /dev/null @@ -1,33 +0,0 @@ - -// cross-browser connection to extension i18n API - -const chrome = chrome || null -const browser = browser || null -const extension = require('extensionizer') -var log = require('loglevel') -window.log = log -let getMessage - -if (extension.i18n && extension.i18n.getMessage) { - getMessage = extension.i18n.getMessage -} else { - // fallback function - log.warn('browser.i18n API not available, calling back to english.') - const msg = require('../app/_locales/en/messages.json') - getMessage = function (key, substitutions) { - if (!msg[key]) { - log.error(key) - throw new Error(key) - } - let phrase = msg[key].message - if (substitutions && substitutions.length) { - phrase = phrase.replace(/\$1/g, substitutions[0]) - if (substitutions.length > 1) { - phrase = phrase.replace(/\$2/g, substitutions[1]) - } - } - return phrase - } -} - -module.exports = getMessage diff --git a/ui/index.js b/ui/index.js index fdb2f23e0..746e28eab 100644 --- a/ui/index.js +++ b/ui/index.js @@ -4,6 +4,7 @@ const Root = require('./app/root') const actions = require('./app/actions') const configureStore = require('./app/store') const txHelper = require('./lib/tx-helper') +const { fetchLocale } = require('./i18n-helper') const { OLD_UI_NETWORK_TYPE, BETA_UI_NETWORK_TYPE } = require('../app/scripts/config').enums global.log = require('loglevel') @@ -18,14 +19,22 @@ function launchMetamaskUi (opts, cb) { // check if we are unlocked first accountManager.getState(function (err, metamaskState) { if (err) return cb(err) - const store = startApp(metamaskState, accountManager, opts) - cb(null, store) + startApp(metamaskState, accountManager, opts) + .then((store) => { + cb(null, store) + }) }) } -function startApp (metamaskState, accountManager, opts) { +async function startApp (metamaskState, accountManager, opts) { // parse opts if (!metamaskState.featureFlags) metamaskState.featureFlags = {} + + const currentLocaleMessages = metamaskState.currentLocale + ? await fetchLocale(metamaskState.currentLocale) + : {} + const enLocaleMessages = await fetchLocale('en') + const store = configureStore({ // metamaskState represents the cross-tab state @@ -34,6 +43,11 @@ function startApp (metamaskState, accountManager, opts) { // appState represents the current tab's popup state appState: {}, + localeMessages: { + current: currentLocaleMessages, + en: enLocaleMessages, + }, + // Which blockchain we are using: networkVersion: opts.networkVersion, }) @@ -55,6 +69,16 @@ function startApp (metamaskState, accountManager, opts) { store.dispatch(actions.updateMetamaskState(metamaskState)) }) + // global metamask api - used by tooling + global.metamask = { + updateCurrentLocale: (code) => { + store.dispatch(actions.updateCurrentLocale(code)) + }, + setProviderType: (type) => { + store.dispatch(actions.setProviderType(type)) + }, + } + // start app render( h(Root, { @@ -99,7 +99,7 @@ JSONStream@^1.0.3: jsonparse "^1.2.0" through ">=2.2.7 <3" -abab@^1.0.3: +abab@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e" @@ -152,7 +152,7 @@ acorn-dynamic-import@^2.0.0: dependencies: acorn "^4.0.3" -acorn-globals@^4.0.0: +acorn-globals@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.1.0.tgz#ab716025dbe17c54d3ef81d32ece2b2d99fe2538" dependencies: @@ -171,7 +171,7 @@ acorn-node@^1.3.0: acorn "^5.4.1" xtend "^4.0.1" -acorn@5.X, acorn@^5.0.0, acorn@^5.0.3, acorn@^5.1.2, acorn@^5.2.1: +acorn@5.X, acorn@^5.0.0, acorn@^5.0.3, acorn@^5.2.1: version "5.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.3.0.tgz#7446d39459c54fb49a80e6ee6478149b940ec822" @@ -183,7 +183,7 @@ acorn@^4.0.3: version "4.0.13" resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" -acorn@^5.4.1: +acorn@^5.3.0, acorn@^5.4.1: version "5.5.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9" @@ -2339,6 +2339,16 @@ chokidar@^2.0.0: optionalDependencies: fsevents "^1.0.0" +chromedriver@^2.34.1: + version "2.37.0" + resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-2.37.0.tgz#e7867c8236f6bb89024737bbffc9a4b33ded658b" + dependencies: + del "^3.0.0" + extract-zip "^1.6.5" + kew "^0.7.0" + mkdirp "^0.5.1" + request "^2.83.0" + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -2378,10 +2388,6 @@ cli-width@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" -client-sw-ready-event@^3.3.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/client-sw-ready-event/-/client-sw-ready-event-3.4.0.tgz#ff486461769055e7748570f1aef102b8675b66d0" - cliui@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" @@ -2642,7 +2648,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@^1.4.3, concat-stream@^1.4.6, concat-stream@^1.5.0, concat-stream@^1.5.1, concat-stream@^1.6.0, concat-stream@~1.6.0: +concat-stream@1.6.0, concat-stream@^1.4.3, concat-stream@^1.4.6, concat-stream@^1.5.0, concat-stream@^1.5.1, concat-stream@^1.6.0, concat-stream@~1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" dependencies: @@ -2698,7 +2704,7 @@ content-disposition@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" -content-type-parser@^1.0.1: +content-type-parser@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.2.tgz#caabe80623e63638b2502fd4c7f12ff4ce2352e7" @@ -2747,6 +2753,10 @@ core-js@^2.2.0, core-js@^2.4.0, core-js@^2.5.0: version "2.5.3" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e" +core-js@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.3.0.tgz#fab83fbb0b2d8dc85fa636c4b9d34c75420c6d65" + core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" @@ -3437,7 +3447,7 @@ duplexer@^0.1.1, duplexer@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" -duplexify@^3.1.2, duplexify@^3.4.2, duplexify@^3.5.0: +duplexify@^3.1.2, duplexify@^3.4.2: version "3.5.1" resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.1.tgz#4e1516be68838bc90a49994f0b39a6e5960befcd" dependencies: @@ -3730,6 +3740,10 @@ es6-promise@^4.0.3: version "4.2.4" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.4.tgz#dc4221c2b16518760bd8c39a52d8f356fc00ed29" +es6-promise@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.0.2.tgz#010d5858423a5f118979665f46486a95c6ee2bb6" + es6-promisify@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" @@ -3824,11 +3838,11 @@ eslint-plugin-chai@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/eslint-plugin-chai/-/eslint-plugin-chai-0.0.1.tgz#9a1dea58b335c31242219d059b37ffb14309f6e1" -eslint-plugin-mocha@^4.9.0: - version "4.11.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-mocha/-/eslint-plugin-mocha-4.11.0.tgz#91193a2f55e20a5e35974054a0089d30198ee578" +eslint-plugin-mocha@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-mocha/-/eslint-plugin-mocha-5.0.0.tgz#43946a7ecaf39039eb3ee20635ebd4cc19baf6dd" dependencies: - ramda "^0.24.1" + ramda "^0.25.0" eslint-plugin-react@^7.4.0: version "7.5.1" @@ -4317,12 +4331,12 @@ ethjs-format@0.2.3: number-to-bn "1.7.0" strip-hex-prefix "1.0.0" -ethjs-format@0.2.4: - version "0.2.4" - resolved "https://registry.yarnpkg.com/ethjs-format/-/ethjs-format-0.2.4.tgz#5bbbc44a5ad24e68ab393312ff9039a73b65bf81" +ethjs-format@0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/ethjs-format/-/ethjs-format-0.2.5.tgz#44f30abee17b074d7162d2c886abffd065828925" dependencies: bn.js "4.11.6" - ethjs-schema "^0.1.9" + ethjs-schema "0.2.0" ethjs-util "0.1.3" is-hex-prefixed "1.0.0" number-to-bn "1.7.0" @@ -4348,26 +4362,30 @@ ethjs-query@^0.2.4, ethjs-query@^0.2.6, ethjs-query@^0.2.9: ethjs-format "0.2.2" ethjs-rpc "0.1.5" -ethjs-query@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/ethjs-query/-/ethjs-query-0.3.2.tgz#f488a48ce1994cd4c77eccb7b52902c6f29cfd85" +ethjs-query@^0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/ethjs-query/-/ethjs-query-0.3.4.tgz#068a8b268fe045acd2dfdf167bb740b12e596bc3" dependencies: - ethjs-format "0.2.4" - ethjs-rpc "0.1.8" + ethjs-format "0.2.5" + ethjs-rpc "0.1.9" ethjs-rpc@0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/ethjs-rpc/-/ethjs-rpc-0.1.5.tgz#099e22f27dc4c18b6978a485fc36b1b0f7969080" -ethjs-rpc@0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/ethjs-rpc/-/ethjs-rpc-0.1.8.tgz#1676740e41c7228196a71189d33f15c9c85b599d" +ethjs-rpc@0.1.9: + version "0.1.9" + resolved "https://registry.yarnpkg.com/ethjs-rpc/-/ethjs-rpc-0.1.9.tgz#389dcd61be52e72bc47111a75805f8e45882faea" ethjs-schema@0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/ethjs-schema/-/ethjs-schema-0.1.5.tgz#59740e3b3977bcdbb9b11bc3068201e8aceabb0d" -ethjs-schema@^0.1.6, ethjs-schema@^0.1.9: +ethjs-schema@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/ethjs-schema/-/ethjs-schema-0.2.0.tgz#07b46d4f55b792a846c90a79f330d31d112cca38" + +ethjs-schema@^0.1.6: version "0.1.9" resolved "https://registry.yarnpkg.com/ethjs-schema/-/ethjs-schema-0.1.9.tgz#858c2a5da706ae04812b4ce8b1eb4b4921e33092" @@ -4644,6 +4662,15 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" +extract-zip@^1.6.5: + version "1.6.6" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.6.tgz#1290ede8d20d0872b429fd3f351ca128ec5ef85c" + dependencies: + concat-stream "1.6.0" + debug "2.6.9" + mkdirp "0.5.0" + yauzl "2.4.1" + extsprintf@1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" @@ -4715,6 +4742,12 @@ fbjs@^0.8.1, fbjs@^0.8.16, fbjs@^0.8.9: setimmediate "^1.0.5" ua-parser-js "^0.7.9" +fd-slicer@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" + dependencies: + pend "~1.2.0" + fetch-ponyfill@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/fetch-ponyfill/-/fetch-ponyfill-4.1.0.tgz#ae3ce5f732c645eab87e4ae8793414709b239893" @@ -4939,10 +4972,6 @@ forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" -fork-stream@^0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/fork-stream/-/fork-stream-0.0.4.tgz#db849fce77f6708a5f8f386ae533a0907b54ae70" - form-data@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.0.0.tgz#6f0aebadcc5da16c13e1ecc11137d85f9b883b25" @@ -5130,6 +5159,10 @@ get-func-name@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" +get-own-enumerable-property-symbols@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-2.0.1.tgz#5c4ad87f2834c4b9b4e84549dc1e0650fb38c24b" + get-stdin@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-3.0.2.tgz#c1ced24b9039b38ded85bdf161e57713b6dd4abe" @@ -5408,6 +5441,17 @@ gulp-cli@^2.0.0: v8flags "^3.0.1" yargs "^7.1.0" +gulp-debug@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/gulp-debug/-/gulp-debug-3.2.0.tgz#45aba4439fa79fe0788f6a411ee0778f4492dfa5" + dependencies: + chalk "^2.3.0" + fancy-log "^1.3.2" + plur "^2.0.0" + stringify-object "^3.0.0" + through2 "^2.0.0" + tildify "^1.1.2" + gulp-eslint@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/gulp-eslint/-/gulp-eslint-4.0.0.tgz#16d9ea4d696e7b7a9d65eeb1aa5bc4ba0a22c7f7" @@ -5415,14 +5459,6 @@ gulp-eslint@^4.0.0: eslint "^4.0.0" gulp-util "^3.0.8" -gulp-if@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/gulp-if/-/gulp-if-2.0.2.tgz#a497b7e7573005041caa2bc8b7dda3c80444d629" - dependencies: - gulp-match "^1.0.3" - ternary-stream "^2.0.1" - through2 "^2.0.1" - gulp-json-editor@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/gulp-json-editor/-/gulp-json-editor-2.2.1.tgz#7c4dd7477e8d06dc5dc49c0b81e745cdb04f97bb" @@ -5444,12 +5480,6 @@ gulp-livereload@^3.8.1: lodash.assign "^3.0.0" mini-lr "^0.1.8" -gulp-match@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/gulp-match/-/gulp-match-1.0.3.tgz#91c7c0d7f29becd6606d57d80a7f8776a87aba8e" - dependencies: - minimatch "^3.0.3" - gulp-replace@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/gulp-replace/-/gulp-replace-0.6.1.tgz#11bf8c8fce533e33e2f6a8f2f430b955ba0be066" @@ -5823,7 +5853,7 @@ hosted-git-info@^2.1.4: version "2.5.0" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" -html-encoding-sniffer@^1.0.1: +html-encoding-sniffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" dependencies: @@ -6013,6 +6043,10 @@ immediate@^3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.2.3.tgz#d140fa8f614659bd6541233097ddaac25cdd991c" +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -6353,6 +6387,10 @@ is-number@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" +is-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + is-odd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-1.0.0.tgz#3b8a932eb028b3775c39bb09e91767accdb69088" @@ -6641,34 +6679,36 @@ jsdom-global@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/jsdom-global/-/jsdom-global-3.0.2.tgz#6bd299c13b0c4626b2da2c0393cd4385d606acb9" -jsdom@^11.1.0: - version "11.5.1" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.5.1.tgz#5df753b8d0bca20142ce21f4f6c039f99a992929" +jsdom@^11.2.0: + version "11.6.2" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.6.2.tgz#25d1ef332d48adf77fc5221fe2619967923f16bb" dependencies: - abab "^1.0.3" - acorn "^5.1.2" - acorn-globals "^4.0.0" + abab "^1.0.4" + acorn "^5.3.0" + acorn-globals "^4.1.0" array-equal "^1.0.0" browser-process-hrtime "^0.1.2" - content-type-parser "^1.0.1" + content-type-parser "^1.0.2" cssom ">= 0.3.2 < 0.4.0" cssstyle ">= 0.2.37 < 0.3.0" domexception "^1.0.0" escodegen "^1.9.0" - html-encoding-sniffer "^1.0.1" + html-encoding-sniffer "^1.0.2" left-pad "^1.2.0" nwmatcher "^1.4.3" - parse5 "^3.0.2" - pn "^1.0.0" + parse5 "4.0.0" + pn "^1.1.0" request "^2.83.0" - request-promise-native "^1.0.3" - sax "^1.2.1" - symbol-tree "^3.2.1" + request-promise-native "^1.0.5" + sax "^1.2.4" + symbol-tree "^3.2.2" tough-cookie "^2.3.3" + w3c-hr-time "^1.0.1" webidl-conversions "^4.0.2" - whatwg-encoding "^1.0.1" - whatwg-url "^6.3.0" - xml-name-validator "^2.0.1" + whatwg-encoding "^1.0.3" + whatwg-url "^6.4.0" + ws "^4.0.0" + xml-name-validator "^3.0.0" jsesc@^1.3.0: version "1.3.0" @@ -6833,6 +6873,16 @@ jsx-ast-utils@^2.0.0: dependencies: array-includes "^3.0.3" +jszip@^3.1.3: + version "3.1.5" + resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.1.5.tgz#e3c2a6c6d706ac6e603314036d43cd40beefdf37" + dependencies: + core-js "~2.3.0" + es6-promise "~3.0.2" + lie "~3.1.0" + pako "~1.0.2" + readable-stream "~2.0.6" + just-debounce@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.0.0.tgz#87fccfaeffc0b68cd19d55f6722943f929ea35ea" @@ -6911,6 +6961,10 @@ keccakjs@^0.2.0: browserify-sha3 "^0.0.1" sha3 "^1.1.0" +kew@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/kew/-/kew-0.7.0.tgz#79d93d2d33363d6fdd2970b335d9141ad591d79b" + kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.1.0, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -7076,6 +7130,12 @@ libqp@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/libqp/-/libqp-1.1.0.tgz#f5e6e06ad74b794fb5b5b66988bf728ef1dedbe8" +lie@~3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + dependencies: + immediate "~3.0.5" + liftoff@^2.3.0: version "2.5.0" resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-2.5.0.tgz#2009291bb31cea861bbf10a7c15a28caf75c31ec" @@ -7587,12 +7647,6 @@ merge-source-map@^1.0.2: dependencies: source-map "^0.6.1" -merge-stream@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" - dependencies: - readable-stream "^2.0.1" - merkle-patricia-tree@^2.1.2: version "2.3.0" resolved "https://registry.yarnpkg.com/merkle-patricia-tree/-/merkle-patricia-tree-2.3.0.tgz#84c606232ef343f1b96fc972e697708754f08573" @@ -7759,7 +7813,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" -"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2: +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.2: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: @@ -7792,6 +7846,12 @@ mkdirp@0.0.x: version "0.0.7" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.0.7.tgz#d89b4f0e4c3e5e5ca54235931675e094fe1a5072" +mkdirp@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12" + dependencies: + minimist "0.0.8" + mkdirp@0.5.1, mkdirp@0.x.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" @@ -8537,7 +8597,7 @@ os-locale@^2.0.0: lcid "^1.0.0" mem "^1.1.0" -os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -8596,7 +8656,7 @@ pac-resolver@~2.0.0: netmask "~1.0.4" thunkify "~2.1.1" -pako@~1.0.5: +pako@~1.0.2, pako@~1.0.5: version "1.0.6" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258" @@ -8661,7 +8721,11 @@ parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" -parse5@^3.0.1, parse5@^3.0.2: +parse5@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" + +parse5@^3.0.1: version "3.0.3" resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c" dependencies: @@ -8785,6 +8849,10 @@ pbkdf2@^3.0.3, pbkdf2@^3.0.9: safe-buffer "^5.0.1" sha.js "^2.4.8" +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + percentile@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/percentile/-/percentile-1.2.0.tgz#fa3b05c1ffd355b35228529834e5fa37f0bd465d" @@ -8867,9 +8935,9 @@ pluralize@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" -pn@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pn/-/pn-1.0.0.tgz#1cf5a30b0d806cd18f88fc41a6b5d4ad615b3ba9" +pn@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" pojo-migrator@^2.1.0: version "2.1.0" @@ -9244,6 +9312,10 @@ ramda@^0.24.1: version "0.24.1" resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.24.1.tgz#c3b7755197f35b8dc3502228262c4c91ddb6b857" +ramda@^0.25.0: + version "0.25.0" + resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.25.0.tgz#8fdf68231cffa90bc2f9460390a0cb74a29b29a9" + randexp@^0.4.2: version "0.4.6" resolved "https://registry.yarnpkg.com/randexp/-/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3" @@ -9544,7 +9616,7 @@ readable-stream@^2, readable-stream@^2.0.0, readable-stream@^2.0.1, readable-str string_decoder "~1.0.3" util-deprecate "~1.0.1" -readable-stream@~2.0.0, readable-stream@~2.0.5: +readable-stream@~2.0.0, readable-stream@~2.0.5, readable-stream@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" dependencies: @@ -9787,7 +9859,7 @@ request-promise-core@1.1.1: dependencies: lodash "^4.13.1" -request-promise-native@^1.0.3: +request-promise-native@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.5.tgz#5281770f68e0c9719e5163fd3fab482215f4fda5" dependencies: @@ -10105,7 +10177,7 @@ sass-graph@^2.2.4: scss-tokenizer "^0.2.3" yargs "^7.0.0" -sax@^1.2.1: +sax@>=0.6.0, sax@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" @@ -10156,6 +10228,15 @@ secp256k1@^3.0.1: nan "^2.2.1" safe-buffer "^5.1.0" +selenium-webdriver@^3.5.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz#2ba87a1662c020b8988c981ae62cb2a01298eafc" + dependencies: + jszip "^3.1.3" + rimraf "^2.5.4" + tmp "0.0.30" + xml2js "^0.4.17" + semaphore@>=1.0.1, semaphore@^1.0.3, semaphore@^1.0.5: version "1.1.0" resolved "https://registry.yarnpkg.com/semaphore/-/semaphore-1.1.0.tgz#aaad8b86b20fe8e9b32b16dc2ee682a8cd26a8aa" @@ -10304,9 +10385,9 @@ signal-exit@^3.0.0, signal-exit@^3.0.1, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" -sinon@^4.0.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/sinon/-/sinon-4.1.3.tgz#fc599eda47ed9f1a694ce774b94ab44260bd7ac5" +sinon@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-5.0.0.tgz#e6de3b3f7fed338b470f8779dc4bab9fca058894" dependencies: diff "^3.1.0" formatio "1.2.0" @@ -10813,6 +10894,14 @@ string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" +stringify-object@^3.0.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.2.2.tgz#9853052e5a88fb605a44cd27445aa257ad7ffbcd" + dependencies: + get-own-enumerable-property-symbols "^2.0.1" + is-obj "^1.0.1" + is-regexp "^1.0.0" + stringstream@~0.0.4, stringstream@~0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" @@ -11031,7 +11120,15 @@ svg-tags@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" -sw-stream@^2.0.0: +sw-controller@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sw-controller/-/sw-controller-1.0.3.tgz#794b5e3e324cf2c515d12b3df57a56128e67dd1e" + dependencies: + babel-preset-es2015 "^6.22.0" + babel-runtime "^6.23.0" + babelify "^7.3.0" + +sw-stream@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/sw-stream/-/sw-stream-2.0.2.tgz#68cd1ce959f3fe79b76f583f98c9172543880a0f" dependencies: @@ -11047,7 +11144,7 @@ symbol-observable@^1.0.3, symbol-observable@^1.0.4: version "1.1.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.1.0.tgz#5c68fd8d54115d9dfb72a84720549222e8db9b32" -symbol-tree@^3.2.1: +symbol-tree@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" @@ -11126,15 +11223,6 @@ tar@^2.0.0, tar@^2.2.1: fstream "^1.0.2" inherits "2" -ternary-stream@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/ternary-stream/-/ternary-stream-2.0.1.tgz#064e489b4b5bf60ba6a6b7bc7f2f5c274ecf8269" - dependencies: - duplexify "^3.5.0" - fork-stream "^0.0.4" - merge-stream "^1.0.0" - through2 "^2.0.1" - test-exclude@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.1.1.tgz#4d84964b0966b0087ecc334a2ce002d3d9341e26" @@ -11259,6 +11347,12 @@ thunkify@~2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/thunkify/-/thunkify-2.1.2.tgz#faa0e9d230c51acc95ca13a361ac05ca7e04553d" +tildify@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tildify/-/tildify-1.2.0.tgz#dcec03f55dca9b7aa3e5b04f21817eb56e63588a" + dependencies: + os-homedir "^1.0.0" + time-stamp@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" @@ -11286,6 +11380,12 @@ timespan@2.3.x: version "2.3.0" resolved "https://registry.yarnpkg.com/timespan/-/timespan-2.3.0.tgz#4902ce040bd13d845c8f59b27e9d59bad6f39929" +tmp@0.0.30: + version "0.0.30" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" + dependencies: + os-tmpdir "~1.0.1" + tmp@0.0.33, tmp@0.0.x, tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -11863,6 +11963,12 @@ vreme@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/vreme/-/vreme-3.0.2.tgz#4721376b449457fefde8a849d3340933b90b5686" +w3c-hr-time@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045" + dependencies: + browser-process-hrtime "^0.1.2" + walk-sync@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/walk-sync/-/walk-sync-0.3.1.tgz#558a16aeac8c0db59c028b73c66f397684ece465" @@ -11927,14 +12033,14 @@ web3-provider-engine@^13.3.2: xhr "^2.2.0" xtend "^4.0.1" -web3-provider-engine@^13.5.6: - version "13.6.0" - resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-13.6.0.tgz#836f51c4ee48bd7583acf3696033779c704c2214" +web3-provider-engine@^13.8.0: + version "13.8.0" + resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-13.8.0.tgz#4c7c1ad2af5f1fe10343b8a65495879a2f9c00df" dependencies: async "^2.5.0" clone "^2.0.0" eth-block-tracker "^2.2.2" - eth-sig-util "^1.3.0" + eth-sig-util "^1.4.2" ethereumjs-block "^1.2.2" ethereumjs-tx "^1.2.0" ethereumjs-util "^5.1.1" @@ -12025,7 +12131,7 @@ websocket-extensions@>=0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29" -whatwg-encoding@^1.0.1: +whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz#57c235bc8657e914d24e1a397d3c82daee0a6ba3" dependencies: @@ -12035,7 +12141,7 @@ whatwg-fetch@>=0.10.0: version "2.0.3" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84" -whatwg-url@^6.3.0: +whatwg-url@^6.4.0: version "6.4.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.4.0.tgz#08fdf2b9e872783a7a1f6216260a1d66cc722e08" dependencies: @@ -12143,6 +12249,13 @@ ws@1.1.1: options ">=0.0.5" ultron "1.0.x" +ws@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-4.1.0.tgz#a979b5d7d4da68bf54efe0408967c324869a7289" + dependencies: + async-limiter "~1.0.0" + safe-buffer "~5.1.0" + ws@~3.3.1: version "3.3.3" resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" @@ -12180,9 +12293,20 @@ xhr@^2.2.0: parse-headers "^2.0.0" xtend "^4.0.0" -xml-name-validator@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635" +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + +xml2js@^0.4.17: + version "0.4.19" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" + dependencies: + sax ">=0.6.0" + xmlbuilder "~9.0.1" + +xmlbuilder@~9.0.1: + version "9.0.7" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" xmldom@^0.1.19: version "0.1.27" @@ -12354,6 +12478,12 @@ yargs@~3.10.0: decamelize "^1.0.0" window-size "0.1.0" +yauzl@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" + dependencies: + fd-slicer "~1.0.1" + yazl@^2.1.0: version "2.4.3" resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.4.3.tgz#ec26e5cc87d5601b9df8432dbdd3cd2e5173a071" |