diff --git a/.circleci/config.yml b/.circleci/config.yml index b433f85..476b7cc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -20,7 +20,7 @@ jobs: - run: name: webpack and eslint - command: npm run dist + command: npm run build - run: name: Build .XPI diff --git a/.eslintignore b/.eslintignore index e69de29..8d6919b 100644 --- a/.eslintignore +++ b/.eslintignore @@ -0,0 +1,7 @@ +# do not lint/format generated artifacts +dist/ +package-lock.json +# makes sure that eslintrc.js gets linted/formatted +!.eslintrc.js +# don't lint/format package.json since npm install formats it differently by default +package.json diff --git a/.eslintrc.js b/.eslintrc.js index c108f12..618576a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,33 +1,52 @@ +/* eslint-env node */ + "use strict"; +// All Mozilla specific rules and environments at: +// http://firefox-source-docs.mozilla.org/tools/lint/linters/eslint-plugin-mozilla.html + module.exports = { env: { - "node": true + es6: true, }, extends: [ "eslint:recommended", + // list of rules at: https://dxr.mozilla.org/mozilla-central/source/tools/lint/eslint/eslint-plugin-mozilla/lib/configs/recommended.js "plugin:mozilla/recommended", ], - - plugins: [ - "mozilla", - "json" + overrides: [ + { + files: "src/**", + env: { + browser: true, + webextensions: true, + }, + }, ], - + parserOptions: { + ecmaVersion: 8, + sourceType: "module", + ecmaFeatures: { + jsx: false, + experimentalObjectRestSpread: true, + }, + }, + plugins: ["json", "mozilla"], + root: true, rules: { "babel/new-cap": "off", - "comma-dangle": ["error", "always-multiline"], - "eqeqeq": "error", - "indent": ["warn", 2, {SwitchCase: 1}], "mozilla/no-aArgs": "warn", - "mozilla/balanced-listeners": 0, + "mozilla/balanced-listeners": "off", + "comma-dangle": ["error", "always-multiline"], + eqeqeq: "error", + indent: ["warn", 2, { SwitchCase: 1 }], "no-console": "warn", - "no-debugger": "warn", - "no-shadow": ["error"], + "no-var": "error", + "no-shadow": "error", "no-unused-vars": "error", "prefer-const": "warn", - "semi": ["error", "always"], - "require-jsdoc": "warn", + "prefer-spread": "error", + semi: ["error", "always"], "valid-jsdoc": "warn", "max-len": ["warn", 80], }, diff --git a/.gitignore b/.gitignore index 10856d8..b75b390 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,3 @@ node_modules *.xpi *.tgz *.*.swp -dist/ diff --git a/Dockerfile b/Dockerfile index 86a8aeb..4c8425d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,4 +8,4 @@ RUN apt-get update -y && \ apt-get install -y zip firefox xvfb nodejs xsel git ssh openbox && \ npm install -g npm@5.3.0 -ENV PATH="/shield-study-utils/node_modules/.bin:$PATH" +ENV PATH="/shield-study-addon-utils/node_modules/.bin:$PATH" diff --git a/README.md b/README.md index de6c45a..2638281 100644 --- a/README.md +++ b/README.md @@ -6,37 +6,24 @@ [![Build Status](https://travis-ci.org/mozilla/shield-studies-addon-utils.svg?branch=master)](https://travis-ci.org/mozilla/shield-studies-addon-utils) -A Firefox JavaScript module to be bundled with shield study add-ons (as `StudyUtils.jsm`). Provides these capabilities: +APIs and tooling that allows add-on developers to build [Shield/Pioneer](https://wiki.mozilla.org/Firefox/Shield/Shield_Studies) ([Normandy](https://wiki.mozilla.org/Firefox/Shield#Normandy_-_User_Profile_Matching_and_Recipe_Deployment)) study add-ons efficiently. -1. **Suggest variation for a client** (Deterministically! i.e. based on a hash of non-PII user info, they will always get assigned to the same branch every time the study launches) -2. **Report study lifecycle data** using Telemetry -3. **Report feature interaction and success data** using Telemetry -4. **Registers/uregisters the study as an active experiment** (By annotating the Telemetry Environment, marking the user as special in the `main` ping). -5. **Validates schema for study config** -6. **Handles study endings** (endStudy method bundles lots of tasks in one, including appending survey URLs specified in Config.jsm with query strings/sending the user to a survey and uninstalling the add-on) - -The pings end up in the `shield-study` and `shield-study-addon` Telemetry buckets for faster analysis. - -Allows add-on developers to build [Shield Study](https://wiki.mozilla.org/Firefox/Shield/Shield_Studies) ([Normandy](https://wiki.mozilla.org/Firefox/Shield#Normandy_-_User_Profile_Matching_and_Recipe_Deployment)) compatible add-ons without having to think very much. - -## What You are Building +## Overview -* You are building a [legacy add-on](https://developer.mozilla.org/Add-ons/Legacy_add_ons). To deploy these after 57, you will need the magic special signing. -* Shield study add-ons can not be based on Web Extensions [yet](https://github.com/mozilla/shield-studies-addon-utils/issues/45). -* Jetpack / addon-sdk is not at all supported since v4 of this utils library. +* `webExtensionApis` - Firefox WebExtension Experiments APIs providing capabilities for study add-ons that are yet not available in the built-in WebExtension APIs +* `testUtils` - Test utils (helper classes to write functional/unit tests for your study add-on) +* `examples` - Tested and verified example add-ons using the WebExtension Experiments APIs and test utils ## Get started Check out [mozilla/shield-studies-addon-template/](https://github.com/mozilla/shield-studies-addon-template/) to get started with an example study where shield-studies-addon-utils is already installed and configured. -## Installing the `StudyUtils.jsm` in your add-on +## Installing the utils in your add-on ``` -npm install --save-dev shield-studies-addon-utils +npm install --save shield-studies-addon-utils ``` -Copy `dist/StudyUtils.jsm` to your `addon` source directory, where it will be zipped up. - ## Engineering and Process * [Shield article on Mozilla Wiki](https://wiki.mozilla.org/Firefox/Shield) @@ -46,24 +33,69 @@ Copy `dist/StudyUtils.jsm` to your `addon` source directory, where it will be zi * [Long, rambling engineering docs](./docs/engineering.md) * Come to slack: #shield +## WebExtension APIs + +### `browser.study.*` + +Provides these capabilities: + +1. **Suggest variation for a client** (Deterministically! i.e. based on a hash of non-PII user info, they will always get assigned to the same branch every time the study launches) +2. **Report study lifecycle data** using Telemetry +3. **Report feature interaction and success data** using Telemetry +4. **Registers/unregisters the study as an active experiment** (By annotating the Telemetry Environment, marking the user as special in the `main` ping). +5. **Validates schema for study config** +6. **Handles study endings** (endStudy method bundles lots of tasks in one, including appending survey URLs specified in Config.jsm with query strings/sending the user to a survey and uninstalling the add-on) + +To use, copy `webExtensionApis/study/api.js` and `webExtensionApis/study/schema.json` to your add-on's source directory under `privileged/study`, then add-the following to your add-on's manifest.json: + +``` + "experiment_apis": { + "study": { + "schema": "./privileged/study/schema.json", + "parent": { + "scopes": ["addon_parent"], + "script": "./privileged/study/api.js", + "paths": [["study"]] + } + } + }, +``` + +#### Data processing pipelines + +Depending on which data processing pipeline the study add-on is configured to use, the pings end up in different destinations: + +* `shield-parquet` - The pings end up in the `shield-study` and `shield-study-addon` Telemetry buckets for faster analysis. +* `pioneer` - The pings are encrypted and end up in the Pioneer processing pipeline +* `custom-telemetry-events` - The pings end up in the ordinary destination for custom telemetry events + +To use, copy and adjust the files as per the `study` API above. + +### `browser.prefs.*` + +Allows your web extension add-on to set and read preferences. + +## What You are Building + +* You are building . To deploy these after 57, you will need the magic special signing. +* Shield study add-ons can not be based on Web Extensions [yet](https://github.com/mozilla/shield-studies-addon-utils/issues/45). + ## Gotchas, Opinions, Side Effects, and Misfeatures 1. No handling of 'timers'. No saved state at all (including the variation name), unless you handle it yourself. - 2. No 'running' pings in v4 (yet). - 3. User disable also uninstalls (and cleans up). ## Development on the Utils -* open an issue -* hack and file a PR +* Open an issue +* Hack and file a PR ## History of major versions -* v5: (In development) API exposed as a Web Extension Experiment +* v5: (In development) API exposed as a Web Extension Experiment. Minimal viable add-on example added. Test coverage improved. Test utils added. * v4.1: Improved utils for common cases -* v4: First `.jsm` release. Uses packet format for PACKET version 3. +* v4: First `.jsm` release for shipping studies as [legacy add-ons](https://developer.mozilla.org/Add-ons/Legacy_add_ons). Used packet format for PACKET version 3. (Jetpack / addon-sdk is not at all supported since v4 of this utils library) * v3: Attempt to formalize on `shield-study` PACKET version 3. Jetpack based. Prototype used for `raymak/page-reload`. All work abandoned, and no formal npm release in this series. Work done at `v3-shield-packet-format` branch. LAST JETPACK (addon-sdk) RELEASE. * v2: Code refactor to es6 `class` with event models. Added cli tooling. Packet format is still arbitrary and per-study. Jetpack based. Last used in studies in Q2 2017. * v1: Initial work and thinking. Telemetry packets are rather arbitrary. Jetpack based. @@ -72,6 +104,6 @@ Copy `dist/StudyUtils.jsm` to your `addon` source directory, where it will be zi Repositories that should not be used as templates for new studies: - - The incubation repo for the updated structure and contents of this repo, ported to the official template in late 2017. - - A repository that was created in 2017 to help new Shield/Pioneer engineers to quickly get up and running with a Shield add-on, built upon an older and much more verbose add-on template. It's documentation has been ported to the official template repo. - - Despite its name, this repo is for static amo consent pages and does not contain any template for Shield studies +* - The incubation repo for the updated structure and contents of the template repo, ported to the official template in late 2017. +* - A repository that was created in 2017 to help new Shield/Pioneer engineers to quickly get up and running with a Shield add-on, built upon an older and much more verbose add-on template. It's documentation has been ported to the official template repo. +* - Despite its name, this repo is for static amo consent pages and does not contain any template for Shield studies diff --git a/bin/make_xpi.sh b/bin/make_xpi.sh deleted file mode 100755 index 40a5e15..0000000 --- a/bin/make_xpi.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash -cp dist/StudyUtils.jsm test-addon/ - -set -eu - -BASE_DIR="$(dirname "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")""/test-addon" -TMP_DIR=$(mktemp -d) -DEST="${TMP_DIR}/test-addon" -mkdir -p $DEST - -# deletes the temp directory -function cleanup { - rm -rf "$TMP_DIR" -} -trap cleanup EXIT - -while read -r LINE || [[ -n "${LINE}" ]]; do - mkdir -p "$(dirname "${DEST}/${LINE}")" - cp -r "${BASE_DIR}/${LINE}" "$(dirname "${DEST}/${LINE}")" -done < "${BASE_DIR}/build-includes.txt" - -pushd $DEST -zip -r test-addon.xpi * -mv test-addon.xpi $BASE_DIR -echo "created at: ${BASE_DIR}/test-addon.xpi" -popd diff --git a/examples/test-addon/bin/bundle-shield-studies-addon-utils.sh b/examples/test-addon/bin/bundle-shield-studies-addon-utils.sh new file mode 100755 index 0000000..33d78fb --- /dev/null +++ b/examples/test-addon/bin/bundle-shield-studies-addon-utils.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +# fail on any error +set -o errexit + +# always run from the repository root directory +script_path=`dirname $0` +cd "$script_path/../../../" + +# paths +WEBEXTAPIS_PATH="webExtensionApis" +ADDON_SRC_PATH="examples/test-addon/src" + +# bundle the study web extension experiment +mkdir -p $ADDON_SRC_PATH/privileged/study +cp $WEBEXTAPIS_PATH/study/api.js $ADDON_SRC_PATH/privileged/study/api.js +cp $WEBEXTAPIS_PATH/study/schema.json $ADDON_SRC_PATH/privileged/study/schema.json + +# bundle the prefs web extension experiment +mkdir -p $ADDON_SRC_PATH/privileged/prefs +cp $WEBEXTAPIS_PATH/prefs/api.js $ADDON_SRC_PATH/privileged/prefs/api.js +cp $WEBEXTAPIS_PATH/prefs/schema.json $ADDON_SRC_PATH/privileged/prefs/schema.json diff --git a/examples/test-addon/dist/.gitignore b/examples/test-addon/dist/.gitignore new file mode 100644 index 0000000..aca2417 --- /dev/null +++ b/examples/test-addon/dist/.gitignore @@ -0,0 +1,2 @@ +* +!*.gitignore diff --git a/examples/test-addon/src/background.js b/examples/test-addon/src/background.js new file mode 100644 index 0000000..2ff5f72 --- /dev/null +++ b/examples/test-addon/src/background.js @@ -0,0 +1,84 @@ +/* eslint no-console:off */ +/* global studySetup */ + +"use strict"; + +class Study { + constructor(variation) {} + + // Will run only during first install attempt + // Use web extension experiments to get whatever prefs, add-ons, + // telemetry, anything necessary for the check + static async isEligible() { + //browser.prefs.get('my.favorite.pref'); + return true; + } + + // Expiration checks should be implemented in a very reliable way by + // the add-on since Normandy does not handle study expiration in a reliable manner + static async hasExpired() { + return false; + } +} + +/** + * Fired when the extension is first installed, when the extension is updated + * to a new version, and when the browser is updated to a new version. + * @param details + */ +function handleInstalled(details) { + console.log( + "The 'handleInstalled' event was fired.", + details.reason, + details, + ); +} + +/** + * Fired when a profile that has this extension installed first starts up. + * This event is not fired when a private browsing/incognito profile is started. + */ +async function handleStartup() { + console.log("The 'handleStartup' event was fired.", arguments); +} + +// todo: on shutdown +// Run shutdown-related non-privileged code + +browser.runtime.onStartup.addListener(handleStartup); +browser.runtime.onInstalled.addListener(handleInstalled); + +async function initiateStudy() { + // Set dynamic study configuration flags + studySetup.eligible = await Study.isEligible(); + studySetup.expired = await Study.hasExpired(); + // Ensure we have configured study and are supposed to run our feature + await browser.study.configure(studySetup); + // Run the startup study checks + await browser.study.startup(); + // Read the active study variation + const { variation } = await browser.study.info(); + // Initiate our study-specific background logic + new Study(variation); +} + +// Since this is a test-addon, we don't initiate any code directly, but wait +// for events sent by tests. This allows us to control and test the execution +// properly. +browser.runtime.onMessage.addListener((request, sender, sendResponse) => { + console.log("request", request); + if (request === "test:initiateStudy") { + initiateStudy(); + } +}); + +// The tests that probe the web extensions APIs directly rely on an extension +// page opening up in a new window/tab. +// For more information, see shield-studies-addon-utils/testUtils/executeJs.js +const createData = { + type: "detached_panel", + url: "extension-page-for-tests/index.html", + width: 500, + height: 500, +}; +const creating = browser.windows.create(createData); diff --git a/examples/test-addon/src/extension-page-for-tests/index.html b/examples/test-addon/src/extension-page-for-tests/index.html new file mode 100644 index 0000000..22c39b4 --- /dev/null +++ b/examples/test-addon/src/extension-page-for-tests/index.html @@ -0,0 +1,31 @@ + + + + + + + + + +

Shield Study Utils Test Add-on

+

This is an extension page for shield-studies-addon-utils/test-addon

+ +

This add-on initiates no background logic on it's own, so that the tests + can test each lifecycle event in isolation.

+ +

For manual testing, use the buttons below to run the code + corresponding to each lifecycle event.

+ +

+ +

+ + + + diff --git a/examples/test-addon/src/extension-page-for-tests/page.js b/examples/test-addon/src/extension-page-for-tests/page.js new file mode 100644 index 0000000..3e27ec9 --- /dev/null +++ b/examples/test-addon/src/extension-page-for-tests/page.js @@ -0,0 +1,9 @@ +document.addEventListener("click", async e => { + function handleError(error) { + console.error(error); + } + + if (e.target.id === "initiateStudy-button") { + await browser.runtime.sendMessage("test:initiateStudy"); + } +}); diff --git a/examples/test-addon/src/icons/LICENSE b/examples/test-addon/src/icons/LICENSE new file mode 100644 index 0000000..fcd8e26 --- /dev/null +++ b/examples/test-addon/src/icons/LICENSE @@ -0,0 +1 @@ +All icons are public domain and came from https://openclipart.org/. diff --git a/examples/test-addon/src/icons/shield-icon.svg b/examples/test-addon/src/icons/shield-icon.svg new file mode 100644 index 0000000..3ad3e5f --- /dev/null +++ b/examples/test-addon/src/icons/shield-icon.svg @@ -0,0 +1,281 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + Openclipart + + + Shield Icon + 2010-09-19T03:15:30 + Here is an icon depicting a shield bearing a star. Use it to depict security, strength etc. Easily modifiable to incorporate a different emblem such as a sword. Enjoy! + https://openclipart.org/detail/85567/shield-icon-by-marricklip14 + + + marricklip14 + + + + + Emblem + Icon Star + Security + Shield + Strength + + + + + + + + + + + diff --git a/examples/test-addon/src/manifest.json b/examples/test-addon/src/manifest.json new file mode 100644 index 0000000..7fb2753 --- /dev/null +++ b/examples/test-addon/src/manifest.json @@ -0,0 +1,41 @@ +{ + "name": "Shield Utils Test Add-on", + "description": "Used for functional testing of shield-studies-addon-utils", + "version": "1.0.0", + "manifest_version": 2, + "applications": { + "gecko": { + "id": "shield-utils-test-addon@shield.mozilla.org", + "strict_min_version": "59.0" + } + }, + "experiment_apis": { + "prefs": { + "schema": "./privileged/prefs/schema.json", + "parent": { + "scopes": ["addon_parent"], + "script": "./privileged/prefs/api.js", + "paths": [["prefs"]] + } + }, + "study": { + "schema": "./privileged/study/schema.json", + "parent": { + "scopes": ["addon_parent"], + "script": "./privileged/study/api.js", + "paths": [["study"]] + } + } + }, + "background": { + "scripts": ["studySetup.js", "background.js"] + }, + "icons": { + "48": "icons/shield-icon.svg" + }, + "browser_action": { + "browser_style": true, + "default_icon": "icons/shield-icon.svg", + "default_title": "Test" + } +} diff --git a/examples/test-addon/src/privileged/.gitignore b/examples/test-addon/src/privileged/.gitignore new file mode 100644 index 0000000..3c31506 --- /dev/null +++ b/examples/test-addon/src/privileged/.gitignore @@ -0,0 +1,3 @@ +# ignore APIs that are bundled from shield-studies-addon-utils +study/ +prefs/ diff --git a/examples/test-addon/src/studySetup.js b/examples/test-addon/src/studySetup.js new file mode 100644 index 0000000..b000565 --- /dev/null +++ b/examples/test-addon/src/studySetup.js @@ -0,0 +1,83 @@ +const studySetup = { + study: { + /** Required for studyUtils.setup(): + * + * - studyName + * - endings: + * - map of endingName: configuration + * - telemetry + * - boolean send + * - boolean removeTestingFlag + * + * All other keys are optional. + */ + + // will be used activeExperiments tagging + studyName: "shield-utils-test", + + /** **endings** + * - keys indicate the 'endStudy' even that opens these. + * - urls should be static (data) or external, because they have to + * survive uninstall + * - If there is no key for an endStudy reason, no url will open. + * - usually surveys, orientations, explanations + */ + endings: { + /** standard endings */ + "user-disable": { + baseUrl: "http://www.example.com/?reason=user-disable", + }, + ineligible: { + baseUrl: "http://www.example.com/?reason=ineligible", + }, + expired: { + baseUrl: "http://www.example.com/?reason=expired", + }, + /** User defined endings */ + "used-often": { + baseUrl: "http://www.example.com/?reason=used-often", + study_state: "ended-positive", // neutral is default + }, + "a-non-url-opening-ending": { + study_state: "ended-neutral", + baseUrl: null, + }, + "introduction-leave-study": { + study_state: "ended-negative", + baseUrl: "http://www.example.com/?reason=introduction-leave-study", + }, + }, + telemetry: { + send: true, // assumed false. Actually send pings? + removeTestingFlag: false, // Marks pings to be discarded, set true for to have the pings processed in the pipeline + // TODO "onInvalid": "throw" // invalid packet for schema? throw||log + }, + }, + + /* Button study branches and sample weights + - test kittens vs. puppies if we can only have one. + - downweight lizards. Lizards is a 'poison' branch, meant to + help control for novelty effect + */ + weightedVariations: [ + { + name: "kittens", + weight: 1.5, + }, + { + name: "puppers", + weight: 1.5, + }, + { + name: "lizard", + weight: 1, + }, // we want more puppers in our sample + ], + + /** + * Change this preference to be able to test the add-on behavior in different study + * variations/branches (or leave it unset to use the automatic assigning + * of a study variation/branch from weightedVariations in Config.jsm) + */ + variationOverridePreference: "extensions.button_icon_preference.variation", +}; diff --git a/examples/test-addon/test/functional/shield_utils_test.js b/examples/test-addon/test/functional/shield_utils_test.js new file mode 100644 index 0000000..ed16e75 --- /dev/null +++ b/examples/test-addon/test/functional/shield_utils_test.js @@ -0,0 +1,270 @@ +/* eslint-env node, mocha */ + +const assert = require("assert"); +const utils = require("./utils"); +const firefox = require("selenium-webdriver/firefox"); +const Context = firefox.Context; + +// TODO create new profile per test? +// then we can test with a clean profile every time + +describe("Shield Study Add-on Utils Functional Tests", function() { + // This gives Firefox time to start, and us a bit longer during some of the tests. + this.timeout(15000); + + let driver; + + before(async () => { + driver = await utils.setup.promiseSetupDriver(utils.FIREFOX_PREFERENCES); + // install the addon (note: returns addon id) + await utils.setup.installAddon(driver); + }); + + // hint: skipping driver.quit() may be useful when debugging failed tests, + // leaving the browser open allowing inspection of the ui and browser logs + after(() => driver.quit()); + + it("should be able to access window.browser from the extension page for tests", async () => { + const hasAccessToWebExtensionApi = await utils.executeJs.executeAsyncScriptInExtensionPageForTests( + driver, + async callback => { + callback(typeof browser === "object"); + }, + ); + assert(hasAccessToWebExtensionApi); + }); + + it("should be able to access study WebExtensions API from the extension page for tests", async () => { + const hasAccessToShieldUtilsWebExtensionApi = await utils.executeJs.executeAsyncScriptInExtensionPageForTests( + driver, + async callback => { + callback(browser && typeof browser.study === "object"); + }, + ); + assert(hasAccessToShieldUtilsWebExtensionApi); + }); + + it("should return the correct variation based on specific weightedVariations", async () => { + const chosenVariation = await utils.executeJs.executeAsyncScriptInExtensionPageForTests( + driver, + async callback => { + const weightedVariations = [ + { + name: "control", + weight: 1, + }, + { + name: "kittens", + weight: 1.5, + }, + { + name: "puppers", + weight: 2, + }, + ]; + + const fraction = 0.3; + const variation = await browser.study.deterministicVariation( + weightedVariations, + fraction, + ); + + callback(variation); + }, + ); + assert(chosenVariation.name === "kittens"); + }); + + it("telemetry should be working", async () => { + const shieldTelemetryPing = await driver.executeAsyncScript( + async callback => { + const { fakeSetup, getMostRecentPingsByType } = Components.utils.import( + "resource://test-addon/utils.jsm", + {}, + ); + const { studyUtils } = Components.utils.import( + "resource://test-addon/StudyUtils.jsm", + {}, + ); + Components.utils.import("resource://gre/modules/TelemetryArchive.jsm"); + + fakeSetup(); + + await studyUtils.telemetry({ foo: "bar" }); + + // TODO Fix this hackiness; caused by addClientId option in submitExternalPing + // The ping seems to be sending (appears in about:telemetry) but does not appear + // in the pings array + await new Promise(resolve => setTimeout(resolve, 1000)); + + const shieldPings = await getMostRecentPingsByType( + "shield-study-addon", + ); + callback(shieldPings[0]); + }, + ); + assert(shieldTelemetryPing.payload.data.attributes.foo === "bar"); + }); + + describe('test the library\'s "startup" process', function() { + it("should send the correct ping on first seen", async () => { + const firstSeenPing = await driver.executeAsyncScript(async callback => { + const { fakeSetup, getMostRecentPingsByType } = Components.utils.import( + "resource://test-addon/utils.jsm", + {}, + ); + const { studyUtils } = Components.utils.import( + "resource://test-addon/StudyUtils.jsm", + {}, + ); + Components.utils.import("resource://gre/modules/TelemetryArchive.jsm"); + + fakeSetup(); + + studyUtils.firstSeen(); + + const studyPings = await getMostRecentPingsByType("shield-study"); + callback(studyPings[0]); + }); + assert(firstSeenPing.payload.data.study_state === "enter"); + }); + + it("should set the experiment to active in Telemetry", async () => { + const activeExperiments = await driver.executeAsyncScript( + async callback => { + const { fakeSetup } = Components.utils.import( + "resource://test-addon/utils.jsm", + {}, + ); + const { studyUtils } = Components.utils.import( + "resource://test-addon/StudyUtils.jsm", + {}, + ); + Components.utils.import( + "resource://gre/modules/TelemetryEnvironment.jsm", + ); + + fakeSetup(); + + studyUtils.setActive(); + + callback(TelemetryEnvironment.getActiveExperiments()); + }, + ); + assert(activeExperiments.hasOwnProperty("shield-utils-test")); + }); + + it("should send the correct telemetry ping on first install", async () => { + const installedPing = await driver.executeAsyncScript(async callback => { + const { fakeSetup, getMostRecentPingsByType } = Components.utils.import( + "resource://test-addon/utils.jsm", + {}, + ); + const { studyUtils } = Components.utils.import( + "resource://test-addon/StudyUtils.jsm", + {}, + ); + Components.utils.import("resource://gre/modules/TelemetryArchive.jsm"); + + fakeSetup(); + + await studyUtils.startup({ reason: 5 }); // ADDON_INSTALL = 5 + + const studyPings = await getMostRecentPingsByType("shield-study"); + callback(studyPings[0]); + }); + assert(installedPing.payload.data.study_state === "installed"); + }); + }); + + describe("test the library's endStudy() function", function() { + before(async () => { + await driver.executeAsyncScript(async callback => { + const { fakeSetup } = Components.utils.import( + "resource://test-addon/utils.jsm", + {}, + ); + const { studyUtils } = Components.utils.import( + "resource://test-addon/StudyUtils.jsm", + {}, + ); + + fakeSetup(); + + // TODO add tests for other reasons (?) + await studyUtils.endStudy({ + reason: "expired", + fullname: "TEST_FULLNAME", + }); + callback(); + }); + }); + + it("should set the experiment as inactive", async () => { + const activeExperiments = await driver.executeAsyncScript( + async callback => { + Components.utils.import( + "resource://gre/modules/TelemetryEnvironment.jsm", + ); + callback(TelemetryEnvironment.getActiveExperiments()); + }, + ); + assert(!activeExperiments.hasOwnProperty("shield-utils-test")); + }); + + describe("test the opening of an URL at the end of the study", function() { + it("should open a new tab", async () => { + const newTabOpened = await driver.wait(async () => { + const handles = await driver.getAllWindowHandles(); + return handles.length === 2; // opened a new tab + }, 3000); + assert(newTabOpened); + }); + + it("should open a new tab to the correct URL", async () => { + const currentHandle = await driver.getWindowHandle(); + driver.setContext(Context.CONTENT); + // Find the new window handle. + let newWindowHandle = null; + const handles = await driver.getAllWindowHandles(); + for (const handle of handles) { + if (handle !== currentHandle) { + newWindowHandle = handle; + } + } + const correctURLOpened = await driver.wait(async () => { + await driver.switchTo().window(newWindowHandle); + const currentURL = await driver.getCurrentUrl(); + return currentURL.startsWith( + "http://www.example.com/?reason=expired", + ); + }); + assert(correctURLOpened); + }); + }); + + it("should send the correct reason telemetry", async () => { + const pings = await driver.executeAsyncScript(async callback => { + const { getMostRecentPingsByType } = Components.utils.import( + "resource://test-addon/utils.jsm", + {}, + ); + const studyPings = await getMostRecentPingsByType("shield-study"); + callback(studyPings[1]); // ping before the most recent ping + }); + assert(pings.payload.data.study_state === "expired"); + }); + + it("should send the uninstall telemetry", async () => { + const pings = await driver.executeAsyncScript(async callback => { + const { getMostRecentPingsByType } = Components.utils.import( + "resource://test-addon/utils.jsm", + {}, + ); + const studyPings = await getMostRecentPingsByType("shield-study"); + callback(studyPings[0]); + }); + assert(pings.payload.data.study_state === "exit"); + }); + }); +}); diff --git a/examples/test-addon/test/functional/utils.js b/examples/test-addon/test/functional/utils.js new file mode 100644 index 0000000..41a8e68 --- /dev/null +++ b/examples/test-addon/test/functional/utils.js @@ -0,0 +1,49 @@ +/* eslint-env node */ + +// The geckodriver package downloads and installs geckodriver for us. +// We use it by requiring it. +require("geckodriver"); + +// Preferences set during testing +const FIREFOX_PREFERENCES = { + // Ensure e10s is turned on. + "browser.tabs.remote.autostart": true, + "browser.tabs.remote.autostart.1": true, + "browser.tabs.remote.autostart.2": true, + + // Improve debugging using `browser toolbox`. + "devtools.chrome.enabled": true, + "devtools.debugger.remote-enabled": true, + "devtools.debugger.prompt-connection": false, + + // Removing warning for `about:config` + "general.warnOnAboutConfig": false, + + // Force variation for testing + "extensions.button_icon_preference.variation": "puppers", + + /** WARNING: Geckodriver sets many additional prefs at: + * https://dxr.mozilla.org/mozilla-central/source/testing/geckodriver/src/prefs.rs + * + * In, particular, this DISABLES actual telemetry uploading + * ("toolkit.telemetry.server", Pref::new("https://%(server)s/dummy/telemetry/")), + * + */ +}; + +// Re-usable test methods from shield-studies-addon-utils +const { executeJs } = require("../../../../testUtils/executeJs"); +const { nav } = require("../../../../testUtils/nav"); +const { pings } = require("../../../../testUtils/pings"); +const { setup } = require("../../../../testUtils/setup"); +const { ui } = require("../../../../testUtils/ui"); + +// What we expose to our add-on-specific tests +module.exports = { + FIREFOX_PREFERENCES, + executeJs, + nav, + pings, + setup, + ui, +}; diff --git a/examples/test-addon/web-ext-config.js b/examples/test-addon/web-ext-config.js new file mode 100644 index 0000000..c6511df --- /dev/null +++ b/examples/test-addon/web-ext-config.js @@ -0,0 +1,19 @@ +/* eslint-env node */ + +const defaultConfig = { + // Global options: + sourceDir: "./src/", + artifactsDir: "./dist/", + ignoreFiles: [".DS_Store"], + // Command options: + build: { + overwriteDest: true, + }, + run: { + firefox: "nightly", + browserConsole: true, + startUrl: ["about:debugging"], + }, +}; + +module.exports = defaultConfig; diff --git a/shield-study-helper-addon/addon/bootstrap.js b/misc/shield-study-helper-addon/addon/bootstrap.js similarity index 74% rename from shield-study-helper-addon/addon/bootstrap.js rename to misc/shield-study-helper-addon/addon/bootstrap.js index 7db1e9b..efcf49a 100644 --- a/shield-study-helper-addon/addon/bootstrap.js +++ b/misc/shield-study-helper-addon/addon/bootstrap.js @@ -3,15 +3,15 @@ /* global __SCRIPT_URI_SPEC__, Feature, studyUtils, config */ /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "(startup|shutdown|install|uninstall)" }]*/ -async function getTelemetryPings (options) { +async function getTelemetryPings(options) { // type is String or Array - const {type, n, timestamp, headersOnly} = options; + const { type, n, timestamp, headersOnly } = options; Components.utils.import("resource://gre/modules/TelemetryArchive.jsm"); // {type, id, timestampCreated} let pings = await TelemetryArchive.promiseArchivedPingList(); if (type) { if (!(type instanceof Array)) { - type = [type]; // Array-ify if it's a string + type = [type]; // Array-ify if it's a string } } if (type) pings = pings.filter(p => type.includes(p.type)); @@ -19,23 +19,26 @@ async function getTelemetryPings (options) { pings.sort((a, b) => b.timestampCreated - a.timestampCreated); if (n) pings = pings.slice(0, n); - const pingData = headersOnly ? pings : pings.map(ping => TelemetryArchive.promiseArchivedPingById(ping.id)); - return Promise.all(pingData) + const pingData = headersOnly + ? pings + : pings.map(ping => TelemetryArchive.promiseArchivedPingById(ping.id)); + return Promise.all(pingData); } -async function pingsReport () { +async function pingsReport() { async function getPings() { const ar = ["shield-study", "shield-study-addon"]; - return getTelemetryPings({type: ["shield-study", "shield-study-addon"]}); + return getTelemetryPings({ type: ["shield-study", "shield-study-addon"] }); } const pings = (await getPings()).reverse(); if (pings.length == 0) { - return {"report": "No pings found"} + return { report: "No pings found" }; } const p0 = pings[0].payload; // print common fields - const report = ` + const report = + ` // common fields branch ${p0.branch} // should describe Question text @@ -43,20 +46,23 @@ study_name ${p0.study_name} addon_version ${p0.addon_version} version ${p0.version} -` + pings.map((p,i)=>`${i} ${p.creationDate} ${p.payload.type} -${JSON.stringify(p.payload.data,null,2)} +` + + pings + .map( + (p, i) => `${i} ${p.creationDate} ${p.payload.type} +${JSON.stringify(p.payload.data, null, 2)} -`).join('\n'); +`, + ) + .join("\n"); - return {"report": report}; + return { report: report }; //pings.forEach(p=>{ // console.log(p.creationDate, p.payload.type); // console.log(JSON.stringify(p.payload.data,null,2)) //}) } - - async function listenFromWebExtension(msg, sender, sendResponse) { //await pingsReport(); console.log(`got ${msg}`); @@ -76,12 +82,11 @@ async function listenFromWebExtension(msg, sender, sendResponse) { return false; } - async function startup(addonData, reason) { - console.log('starting up debugger') + console.log("starting up debugger"); const webExtension = addonData.webExtension; webExtension.startup().then(api => { - const {browser} = api; + const { browser } = api; // messages intended for shieldn: {shield:true,msg=[info|endStudy|telemetry],data=data} browser.runtime.onMessage.addListener(listenFromWebExtension); // other message handlers from your addon, if any diff --git a/shield-study-helper-addon/addon/chrome.manifest b/misc/shield-study-helper-addon/addon/chrome.manifest similarity index 100% rename from shield-study-helper-addon/addon/chrome.manifest rename to misc/shield-study-helper-addon/addon/chrome.manifest diff --git a/shield-study-helper-addon/addon/install.rdf b/misc/shield-study-helper-addon/addon/install.rdf similarity index 100% rename from shield-study-helper-addon/addon/install.rdf rename to misc/shield-study-helper-addon/addon/install.rdf diff --git a/misc/shield-study-helper-addon/addon/webextension/.eslintrc.json b/misc/shield-study-helper-addon/addon/webextension/.eslintrc.json new file mode 100644 index 0000000..5c7cc9e --- /dev/null +++ b/misc/shield-study-helper-addon/addon/webextension/.eslintrc.json @@ -0,0 +1,11 @@ +{ + "env": { + "browser": true, + "es6": true, + "webextensions": true + }, + "extends": ["eslint:recommended"], + "rules": { + "no-console": "warn" + } +} diff --git a/shield-study-helper-addon/addon/webextension/icon.png b/misc/shield-study-helper-addon/addon/webextension/icon.png similarity index 100% rename from shield-study-helper-addon/addon/webextension/icon.png rename to misc/shield-study-helper-addon/addon/webextension/icon.png diff --git a/shield-study-helper-addon/addon/webextension/manifest.json b/misc/shield-study-helper-addon/addon/webextension/manifest.json similarity index 100% rename from shield-study-helper-addon/addon/webextension/manifest.json rename to misc/shield-study-helper-addon/addon/webextension/manifest.json diff --git a/shield-study-helper-addon/addon/webextension/qa.html b/misc/shield-study-helper-addon/addon/webextension/qa.html similarity index 100% rename from shield-study-helper-addon/addon/webextension/qa.html rename to misc/shield-study-helper-addon/addon/webextension/qa.html diff --git a/shield-study-helper-addon/addon/webextension/qa.js b/misc/shield-study-helper-addon/addon/webextension/qa.js similarity index 63% rename from shield-study-helper-addon/addon/webextension/qa.js rename to misc/shield-study-helper-addon/addon/webextension/qa.js index ef036a1..d9f3142 100644 --- a/shield-study-helper-addon/addon/webextension/qa.js +++ b/misc/shield-study-helper-addon/addon/webextension/qa.js @@ -7,26 +7,25 @@ has a bunch of pings and stuff `; -function printReport (text) { +function printReport(text) { console.log(`about to replace: ${text}`); - document.querySelector('#timestamp').textContent=`${new Date()}`; - document.querySelector('#qa').textContent=text; + document.querySelector("#timestamp").textContent = `${new Date()}`; + document.querySelector("#qa").textContent = text; } - -async function tryReportFromFirefox () { - console.log(`has browser runtime? ${browser.runtime}`) +async function tryReportFromFirefox() { + console.log(`has browser runtime? ${browser.runtime}`); if (browser.runtime) { - const reply = await browser.runtime.sendMessage("qa-report") + const reply = await browser.runtime.sendMessage("qa-report"); console.log("got reply!", reply); if (reply) { printReport(reply.report); //console.log("response from legacy add-on: " + reply.content); - }; + } } } -function startup () { +function startup() { printReport(PLACEHOLDER); console.log("asking firefox"); tryReportFromFirefox(); @@ -39,5 +38,4 @@ page starts up. - once it arrives, insert it. */ - -document.addEventListener('DOMContentLoaded', startup); +document.addEventListener("DOMContentLoaded", startup); diff --git a/shield-study-helper-addon/build.sh b/misc/shield-study-helper-addon/build.sh similarity index 100% rename from shield-study-helper-addon/build.sh rename to misc/shield-study-helper-addon/build.sh diff --git a/shield-study-helper-addon/package-lock.json b/misc/shield-study-helper-addon/package-lock.json similarity index 100% rename from shield-study-helper-addon/package-lock.json rename to misc/shield-study-helper-addon/package-lock.json diff --git a/shield-study-helper-addon/package.json b/misc/shield-study-helper-addon/package.json similarity index 100% rename from shield-study-helper-addon/package.json rename to misc/shield-study-helper-addon/package.json diff --git a/shield-study-helper-addon/run-firefox.js b/misc/shield-study-helper-addon/run-firefox.js similarity index 88% rename from shield-study-helper-addon/run-firefox.js rename to misc/shield-study-helper-addon/run-firefox.js index c784775..0307240 100644 --- a/shield-study-helper-addon/run-firefox.js +++ b/misc/shield-study-helper-addon/run-firefox.js @@ -10,7 +10,6 @@ console.log("Starting up firefox"); - require("geckodriver"); const firefox = require("selenium-webdriver/firefox"); const cmd = require("selenium-webdriver/lib/command"); @@ -60,11 +59,11 @@ async function promiseActualBinary(binary) { } } -promiseSetupDriver = async() => { +promiseSetupDriver = async () => { const profile = new firefox.Profile(); // TODO, allow 'actually send telemetry' here. - Object.keys(FIREFOX_PREFERENCES).forEach((key) => { + Object.keys(FIREFOX_PREFERENCES).forEach(key => { profile.setPreference(key, FIREFOX_PREFERENCES[key]); }); @@ -76,7 +75,9 @@ promiseSetupDriver = async() => { .forBrowser("firefox") .setFirefoxOptions(options); - const binaryLocation = await promiseActualBinary(process.env.FIREFOX_BINARY || "nightly"); + const binaryLocation = await promiseActualBinary( + process.env.FIREFOX_BINARY || "nightly", + ); await options.setBinary(new firefox.Binary(binaryLocation)); const driver = await builder.build(); // Firefox will be started up by now @@ -85,21 +86,28 @@ promiseSetupDriver = async() => { return driver; }; -installAddon = async(driver, fileLocation) => { +installAddon = async (driver, fileLocation) => { // references: // https://bugzilla.mozilla.org/show_bug.cgi?id=1298025 // https://github.com/mozilla/geckodriver/releases/tag/v0.17.0 const executor = driver.getExecutor(); - executor.defineCommand("installAddon", "POST", "/session/:sessionId/moz/addon/install"); + executor.defineCommand( + "installAddon", + "POST", + "/session/:sessionId/moz/addon/install", + ); const installCmd = new cmd.Command("installAddon"); const session = await driver.getSession(); - installCmd.setParameters({ sessionId: session.getId(), path: fileLocation, temporary: true }); + installCmd.setParameters({ + sessionId: session.getId(), + path: fileLocation, + temporary: true, + }); return executor.execute(installCmd); }; - -(async() => { +(async () => { try { const driver = await promiseSetupDriver(); @@ -114,7 +122,6 @@ installAddon = async(driver, fileLocation) => { // navigate to a regular page driver.setContext(Context.CONTENT); driver.get("about:debugging"); - } catch (e) { console.error(e); // eslint-disable-line no-console } diff --git a/package-lock.json b/package-lock.json index 935845d..d90dc94 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,9 +1,55 @@ { "name": "shield-studies-addon-utils", - "version": "4.0.0", + "version": "5.0.0-alpha1", "lockfileVersion": 1, "requires": true, "dependencies": { + "@cliqz-oss/firefox-client": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@cliqz-oss/firefox-client/-/firefox-client-0.3.1.tgz", + "integrity": "sha512-RO+Tops/wGnBzWoZYkCraqyh2JqOejqJq5/a4b54HhmjTNSKdUPwAOK17EGg/zPb0nWqkuB7QyZsI9bo+ev8Kw==", + "dev": true, + "requires": { + "colors": "0.5.1", + "js-select": "0.6.0" + }, + "dependencies": { + "colors": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.5.1.tgz", + "integrity": "sha1-fQAj6usVTo7p/Oddy5I9DtFmd3Q=", + "dev": true + } + } + }, + "@cliqz-oss/node-firefox-connect": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@cliqz-oss/node-firefox-connect/-/node-firefox-connect-1.2.1.tgz", + "integrity": "sha512-O/IyiB5pfztCdmxQZg0/xeq5w+YiP3gtJz8d4We2EpLPKzbDVjOrtfLKYgVfm6Ya6mbvDge1uLkSRwaoVCWKnA==", + "dev": true, + "requires": { + "@cliqz-oss/firefox-client": "0.3.1", + "es6-promise": "2.3.0" + } + }, + "@types/node": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.1.tgz", + "integrity": "sha512-xwlHq5DXQFRpe+u6hmmNkzYk/3oxxqDp71a/AJMupOQYmxyaBetqrVMqdNlSQfbg7XTJYD8vARjf3Op06OzdtQ==", + "dev": true + }, + "JSONSelect": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/JSONSelect/-/JSONSelect-0.2.1.tgz", + "integrity": "sha1-QVQYpSbTP+MddLTe+jyDbUhewgM=", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, "acorn": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.1.tgz", @@ -44,10 +90,446 @@ } } }, + "adbkit": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/adbkit/-/adbkit-2.11.0.tgz", + "integrity": "sha512-j2vUhEeZmCiqBP+p77CpPWQTcT20rOmSmRHFUTZUwUpxzeCd3fXop4NAGYztSY9/FNU4bT/qqvYQ4EZKuCXhfA==", + "dev": true, + "requires": { + "adbkit-logcat": "1.1.0", + "adbkit-monkey": "1.0.1", + "bluebird": "2.9.34", + "commander": "2.11.0", + "debug": "2.6.8", + "node-forge": "0.7.5", + "split": "0.3.3" + }, + "dependencies": { + "bluebird": { + "version": "2.9.34", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.9.34.tgz", + "integrity": "sha1-L3tOyAIWMoqf3evfacjUlC/v99g=", + "dev": true + } + } + }, + "adbkit-logcat": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/adbkit-logcat/-/adbkit-logcat-1.1.0.tgz", + "integrity": "sha1-Adf5sM75CTowvLOwB+//MBUIli8=", + "dev": true + }, + "adbkit-monkey": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/adbkit-monkey/-/adbkit-monkey-1.0.1.tgz", + "integrity": "sha1-8pG+cBou/FZ6Y/x6pq/N7TFDC+E=", + "dev": true, + "requires": { + "async": "0.2.10" + }, + "dependencies": { + "async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=", + "dev": true + } + } + }, + "addons-linter": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/addons-linter/-/addons-linter-0.41.0.tgz", + "integrity": "sha512-jrN8OC6HKWv6nadJYOWH/ISiuJrTzBp0Jonfg7xUBPTSo6Lxo/EWBv1s3mSGTErzhiODDAFFsP6QUr76QwfcWA==", + "dev": true, + "requires": { + "ajv": "6.3.0", + "ajv-merge-patch": "3.0.0", + "babel-register": "6.26.0", + "chalk": "2.3.2", + "cheerio": "1.0.0-rc.2", + "columnify": "1.5.4", + "common-tags": "1.7.2", + "crx-parser": "0.1.2", + "deepmerge": "2.1.0", + "dispensary": "0.16.0", + "doctoc": "1.3.1", + "es6-promisify": "5.0.0", + "eslint": "4.19.0", + "eslint-plugin-no-unsafe-innerhtml": "1.0.16", + "esprima": "3.1.3", + "first-chunk-stream": "2.0.0", + "fluent-syntax": "0.6.6", + "glob": "7.1.2", + "is-mergeable-object": "1.1.0", + "jed": "1.1.1", + "os-locale": "2.1.0", + "pino": "4.14.0", + "po2json": "0.4.5", + "postcss": "6.0.19", + "probe-image-size": "4.0.0", + "relaxed-json": "1.0.1", + "semver": "5.5.0", + "shelljs": "0.8.1", + "snyk": "1.70.3", + "source-map-support": "0.5.4", + "strip-bom-stream": "3.0.0", + "tosource": "1.0.0", + "upath": "1.0.4", + "whatwg-url": "6.3.0", + "xmldom": "0.1.27", + "yargs": "11.0.0", + "yauzl": "2.9.1" + }, + "dependencies": { + "acorn": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.5.3.tgz", + "integrity": "sha512-jd5MkIUlbbmb07nXH0DT3y7rDVtkzDi4XZOUVWAer8ajmF/DTSSbl5oNFyDOl/OXA33Bl79+ypHhl2pN20VeOQ==", + "dev": true + }, + "ajv": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.3.0.tgz", + "integrity": "sha1-FlCkERTvAFdMrBC4Ay2PTBSBLac=", + "dev": true, + "requires": { + "fast-deep-equal": "1.0.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "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.0" + } + }, + "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" + } + }, + "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" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "2.0.2" + } + }, + "eslint": { + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.0.tgz", + "integrity": "sha512-r83L5CuqaocDvfwdojbz68b6tCUk8KJkqfppO+gmSAQqYCzTr0bCSMu6A6yFCLKG65j5eKcKUw4Cw4Yl4gfWkg==", + "dev": true, + "requires": { + "ajv": "5.5.2", + "babel-code-frame": "6.22.0", + "chalk": "2.3.2", + "concat-stream": "1.6.0", + "cross-spawn": "5.1.0", + "debug": "3.1.0", + "doctrine": "2.1.0", + "eslint-scope": "3.7.1", + "eslint-visitor-keys": "1.0.0", + "espree": "3.5.4", + "esquery": "1.0.0", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "functional-red-black-tree": "1.0.1", + "glob": "7.1.2", + "globals": "11.4.0", + "ignore": "3.3.3", + "imurmurhash": "0.1.4", + "inquirer": "3.2.0", + "is-resolvable": "1.0.0", + "js-yaml": "3.11.0", + "json-stable-stringify-without-jsonify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.4", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "7.0.0", + "progress": "2.0.0", + "regexpp": "1.1.0", + "require-uncached": "1.0.3", + "semver": "5.5.0", + "strip-ansi": "4.0.0", + "strip-json-comments": "2.0.1", + "table": "4.0.2", + "text-table": "0.2.0" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.0.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + } + } + }, + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "dev": true, + "requires": { + "acorn": "5.5.3", + "acorn-jsx": "3.0.1" + } + }, + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true + }, + "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" + } + }, + "globals": { + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.4.0.tgz", + "integrity": "sha512-Dyzmifil8n/TmSqYDEXbm+C8yitzJQqQIlJQLNRMwa+BOUJpRC19pyVeN12JAjt61xonvXjtff+hJruTRXn5HA==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "js-yaml": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.11.0.tgz", + "integrity": "sha512-saJstZWv7oNeOyBh3+Dx1qWzhW0+e6/8eDzo7p5rDFqxntSztloLtuKu+Ejhtq82jsilwOIZYsCz+lIjthg1Hw==", + "dev": true, + "requires": { + "argparse": "1.0.9", + "esprima": "4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", + "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" + } + }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "dev": true + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + }, + "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.0.3", + "rechoir": "0.6.2" + } + }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0" + } + }, + "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" + } + }, + "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" + } + }, + "table": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", + "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", + "dev": true, + "requires": { + "ajv": "5.5.2", + "ajv-keywords": "2.1.1", + "chalk": "2.3.2", + "lodash": "4.17.4", + "slice-ansi": "1.0.0", + "string-width": "2.1.1" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.0.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + } + } + }, + "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" + } + } + } + }, "adm-zip": { "version": "0.4.7", "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz", - "integrity": "sha1-hgbCy/HEJs6MjsABdER/1Jtur8E=" + "integrity": "sha1-hgbCy/HEJs6MjsABdER/1Jtur8E=", + "dev": true }, "ajv": { "version": "4.11.8", @@ -59,6 +541,22 @@ "json-stable-stringify": "1.0.1" } }, + "ajv-keywords": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", + "dev": true + }, + "ajv-merge-patch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ajv-merge-patch/-/ajv-merge-patch-3.0.0.tgz", + "integrity": "sha1-dvBx45H0Gf6f4/6n6SChrYJLK2E=", + "dev": true, + "requires": { + "fast-json-patch": "1.2.2", + "json-merge-patch": "0.2.3" + } + }, "alce": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/alce/-/alce-1.0.0.tgz", @@ -94,6 +592,24 @@ "repeat-string": "1.6.1" } }, + "anchor-markdown-header": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/anchor-markdown-header/-/anchor-markdown-header-0.5.7.tgz", + "integrity": "sha1-BFBj125qH5zTJ6V6ASaqD97Dcac=", + "dev": true, + "requires": { + "emoji-regex": "6.1.3" + } + }, + "ansi-align": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", + "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", + "dev": true, + "requires": { + "string-width": "2.1.0" + } + }, "ansi-escapes": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-2.0.0.tgz", @@ -112,6 +628,18 @@ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", "dev": true }, + "ansicolors": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", + "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=", + "dev": true + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=", + "dev": true + }, "anymatch": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz", @@ -122,6 +650,42 @@ "micromatch": "2.3.11" } }, + "archiver": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/archiver/-/archiver-2.1.1.tgz", + "integrity": "sha1-/2YrSnggFJSj7lRNOjP+dJZQnrw=", + "dev": true, + "requires": { + "archiver-utils": "1.3.0", + "async": "2.5.0", + "buffer-crc32": "0.2.13", + "glob": "7.1.2", + "lodash": "4.17.4", + "readable-stream": "2.3.3", + "tar-stream": "1.5.5", + "zip-stream": "1.2.0" + } + }, + "archiver-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-1.3.0.tgz", + "integrity": "sha1-5QtMCccL89aA4y/xt5lOn52JUXQ=", + "dev": true, + "requires": { + "glob": "7.1.2", + "graceful-fs": "4.1.11", + "lazystream": "1.0.0", + "lodash": "4.17.4", + "normalize-path": "2.1.1", + "readable-stream": "2.3.3" + } + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, "argparse": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", @@ -146,20 +710,35 @@ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", "dev": true }, - "array-filter": { + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-filter": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", - "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=" + "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", + "dev": true + }, + "array-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", + "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=", + "dev": true }, "array-map": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", - "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=" + "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=", + "dev": true }, "array-reduce": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", - "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=" + "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=", + "dev": true }, "array-union": { "version": "1.0.2", @@ -188,6 +767,18 @@ "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "dev": true + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true + }, "asn1.js": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.1.tgz", @@ -203,10 +794,23 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", + "dev": true, "requires": { "util": "0.10.3" } }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, "async": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz", @@ -222,6 +826,30 @@ "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", "dev": true }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "atob": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.0.tgz", + "integrity": "sha512-SuiKH8vbsOyCALjA/+EINmt/Kdl+TQPrtFgW7XZZcwtryFu9e5kQoX3bjCW6mIvGH1fbeAZZuvwGR5IlBRznGw==", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", + "dev": true + }, "babel-code-frame": { "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz", @@ -233,10 +861,248 @@ "js-tokens": "3.0.2" } }, + "babel-core": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz", + "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "babel-generator": "6.26.1", + "babel-helpers": "6.24.1", + "babel-messages": "6.23.0", + "babel-register": "6.26.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "convert-source-map": "1.5.1", + "debug": "2.6.8", + "json5": "0.5.1", + "lodash": "4.17.4", + "minimatch": "3.0.4", + "path-is-absolute": "1.0.1", + "private": "0.1.8", + "slash": "1.0.0", + "source-map": "0.5.6" + }, + "dependencies": { + "babel-code-frame": { + "version": "6.26.0", + "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", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + } + } + } + }, + "babel-generator": { + "version": "6.26.1", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz", + "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==", + "dev": true, + "requires": { + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "detect-indent": "4.0.0", + "jsesc": "1.3.0", + "lodash": "4.17.4", + "source-map": "0.5.7", + "trim-right": "1.0.1" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-polyfill": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", + "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "core-js": "2.5.4", + "regenerator-runtime": "0.10.5" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=", + "dev": true + } + } + }, + "babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", + "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "dev": true, + "requires": { + "babel-core": "6.26.0", + "babel-runtime": "6.26.0", + "core-js": "2.5.4", + "home-or-tmp": "2.0.0", + "lodash": "4.17.4", + "mkdirp": "0.5.1", + "source-map-support": "0.4.18" + }, + "dependencies": { + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "0.5.6" + } + } + } + }, + "babel-runtime": { + "version": "6.26.0", + "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.4", + "regenerator-runtime": "0.11.1" + } + }, + "babel-template": { + "version": "6.26.0", + "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", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "lodash": "4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "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", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.8", + "globals": "9.18.0", + "invariant": "2.2.4", + "lodash": "4.17.4" + }, + "dependencies": { + "babel-code-frame": { + "version": "6.26.0", + "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", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + } + } + } + }, + "babel-types": { + "version": "6.26.0", + "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", + "esutils": "2.0.2", + "lodash": "4.17.4", + "to-fast-properties": "1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "bail": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.2.tgz", + "integrity": "sha1-99bBcxYwqfnw1NNe0fli4gdKF2Q=", + "dev": true + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "1.0.1", + "class-utils": "0.3.6", + "component-emitter": "1.2.1", + "define-property": "1.0.0", + "isobject": "3.0.1", + "mixin-deep": "1.3.1", + "pascalcase": "0.1.1" + }, + "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" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } }, "base64-js": { "version": "1.2.1", @@ -244,6 +1110,22 @@ "integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==", "dev": true }, + "base64url": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz", + "integrity": "sha1-6sFuA+oUOO/5Qj1puqNiYu0fcLs=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, "big.js": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.1.3.tgz", @@ -256,10 +1138,44 @@ "integrity": "sha1-SOyNFt9Dd+rl+liEaCSAr02Vx3Q=", "dev": true }, + "bl": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "dev": true, + "requires": { + "readable-stream": "2.3.5", + "safe-buffer": "5.1.1" + }, + "dependencies": { + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true + }, + "readable-stream": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.5.tgz", + "integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + } + } + }, "block-stream": { "version": "0.0.9", "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "dev": true, "requires": { "inherits": "2.0.3" } @@ -267,7 +1183,8 @@ "bluebird": { "version": "3.4.6", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.6.tgz", - "integrity": "sha1-AdqNgh2HgT0ViWfnQ9X+bGLPjA8=" + "integrity": "sha1-AdqNgh2HgT0ViWfnQ9X+bGLPjA8=", + "dev": true }, "bn.js": { "version": "4.11.7", @@ -275,10 +1192,86 @@ "integrity": "sha512-LxFiV5mefv0ley0SzqkOPR1bC4EbpPx8LkOz5vMe/Yi15t5hzwgO/G+tc7wOtL4PZTYjwHu8JnEiSLumuSjSfA==", "dev": true }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "dev": true, + "requires": { + "hoek": "4.2.1" + } + }, + "bops": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/bops/-/bops-0.1.1.tgz", + "integrity": "sha1-Bi4CqNqoAfoQ8uXb5nQM/4Af4X4=", + "dev": true, + "requires": { + "base64-js": "0.0.2", + "to-utf8": "0.0.1" + }, + "dependencies": { + "base64-js": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.2.tgz", + "integrity": "sha1-Ak8Pcq+iW3X5wO5zzU9V7Bvtl4Q=", + "dev": true + } + } + }, + "boundary": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/boundary/-/boundary-1.0.1.tgz", + "integrity": "sha1-TWfcJgLAzBbdm85+v4fpSCkPWBI=", + "dev": true + }, + "boxen": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-0.3.1.tgz", + "integrity": "sha1-p9iYJDrmIvertrtgTXQKdsalRhs=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "filled-array": "1.1.0", + "object-assign": "4.1.1", + "repeating": "2.0.1", + "string-width": "1.0.2", + "widest-line": "1.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "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" + } + }, + "string-width": { + "version": "1.0.2", + "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", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + } + } + }, "brace-expansion": { "version": "1.1.8", "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", "concat-map": "0.0.1" @@ -304,7 +1297,8 @@ "browser-stdout": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", - "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=" + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "dev": true }, "browserify-aes": { "version": "1.0.6", @@ -386,6 +1380,18 @@ "isarray": "1.0.0" } }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "dev": true + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=", + "dev": true + }, "buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", @@ -404,6 +1410,43 @@ "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", "dev": true }, + "bunyan": { + "version": "1.8.12", + "resolved": "https://registry.npmjs.org/bunyan/-/bunyan-1.8.12.tgz", + "integrity": "sha1-8VDw9nSKvdcq6uhPBEA74u8RN5c=", + "dev": true, + "requires": { + "dtrace-provider": "0.8.6", + "moment": "2.22.0", + "mv": "2.1.1", + "safe-json-stringify": "1.1.0" + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "1.0.0", + "component-emitter": "1.2.1", + "get-value": "2.0.6", + "has-value": "1.0.0", + "isobject": "3.0.1", + "set-value": "2.0.0", + "to-object-path": "0.3.0", + "union-value": "1.0.0", + "unset-value": "1.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, "caller-path": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", @@ -428,7 +1471,20 @@ "capture-stack-trace": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz", - "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=" + "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "ccount": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.0.2.tgz", + "integrity": "sha1-U7ai+BW7d7nChx97mnLDol8djok=", + "dev": true }, "center-align": { "version": "0.1.3", @@ -453,21 +1509,81 @@ "supports-color": "2.0.0" } }, - "chokidar": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", - "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", - "dev": true, - "requires": { - "anymatch": "1.3.0", - "async-each": "1.0.1", - "fsevents": "1.1.2", - "glob-parent": "2.0.0", - "inherits": "2.0.3", - "is-binary-path": "1.0.1", - "is-glob": "2.0.1", - "path-is-absolute": "1.0.1", - "readdirp": "2.1.0" + "character-entities": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.1.tgz", + "integrity": "sha1-92hxvl72bdt/j440eOzDdMJ9bco=", + "dev": true + }, + "character-entities-html4": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.1.tgz", + "integrity": "sha1-NZoqSg9+KdPcKsmb2+Ie45Q46lA=", + "dev": true + }, + "character-entities-legacy": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.1.tgz", + "integrity": "sha1-9Ad53xoQGHK7UQo9KV4fzPFHIC8=", + "dev": true + }, + "character-reference-invalid": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.1.tgz", + "integrity": "sha1-lCg191Dk7GGjCOYMLvjMEBEgLvw=", + "dev": true + }, + "cheerio": { + "version": "1.0.0-rc.2", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.2.tgz", + "integrity": "sha1-S59TqBsn5NXawxwP/Qz6A8xoMNs=", + "dev": true, + "requires": { + "css-select": "1.2.0", + "dom-serializer": "0.1.0", + "entities": "1.1.1", + "htmlparser2": "3.9.2", + "lodash": "4.17.4", + "parse5": "3.0.3" + }, + "dependencies": { + "entities": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", + "dev": true + }, + "htmlparser2": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz", + "integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=", + "dev": true, + "requires": { + "domelementtype": "1.3.0", + "domhandler": "2.3.0", + "domutils": "1.5.1", + "entities": "1.1.1", + "inherits": "2.0.3", + "readable-stream": "2.3.3" + } + } + } + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "dev": true, + "requires": { + "anymatch": "1.3.0", + "async-each": "1.0.1", + "fsevents": "1.1.2", + "glob-parent": "2.0.0", + "inherits": "2.0.3", + "is-binary-path": "1.0.1", + "is-glob": "2.0.1", + "path-is-absolute": "1.0.1", + "readdirp": "2.1.0" } }, "cipher-base": { @@ -486,6 +1602,92 @@ "integrity": "sha1-vos2rvzN6LPKeqLWr8B6NyQsDS0=", "dev": true }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "3.1.0", + "define-property": "0.2.5", + "isobject": "3.0.1", + "static-extend": "0.1.2" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "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" + } + }, + "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==", + "dev": true + } + } + }, "cli": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", @@ -496,6 +1698,12 @@ "glob": "7.1.2" } }, + "cli-boxes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", + "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", + "dev": true + }, "cli-cursor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", @@ -511,6 +1719,143 @@ "integrity": "sha1-sjTKIJsp72b8UY2bmNWEewDt8Ao=", "dev": true }, + "clite": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/clite/-/clite-0.3.0.tgz", + "integrity": "sha1-5/y8jMW9Pn+LhO1I2xLpR0zHNEE=", + "dev": true, + "requires": { + "abbrev": "1.1.1", + "debug": "2.6.8", + "es6-promise": "3.3.1", + "lodash.defaults": "4.2.0", + "lodash.defaultsdeep": "4.6.0", + "lodash.mergewith": "4.6.1", + "then-fs": "2.0.0", + "update-notifier": "0.6.3", + "yargs": "4.8.1" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" + } + }, + "configstore": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-2.1.0.tgz", + "integrity": "sha1-c3o6cDbpiGECqmCZ5HuzOrGroaE=", + "dev": true, + "requires": { + "dot-prop": "3.0.0", + "graceful-fs": "4.1.11", + "mkdirp": "0.5.1", + "object-assign": "4.1.1", + "os-tmpdir": "1.0.2", + "osenv": "0.1.5", + "uuid": "2.0.3", + "write-file-atomic": "1.3.4", + "xdg-basedir": "2.0.0" + } + }, + "es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "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" + } + }, + "string-width": { + "version": "1.0.2", + "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", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "update-notifier": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-0.6.3.tgz", + "integrity": "sha1-d23sjaoT6WKjQeih2YNUMGtnrgg=", + "dev": true, + "requires": { + "boxen": "0.3.1", + "chalk": "1.1.3", + "configstore": "2.1.0", + "is-npm": "1.0.0", + "latest-version": "2.0.0", + "semver-diff": "2.1.0" + } + }, + "uuid": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", + "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=", + "dev": true + }, + "window-size": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=", + "dev": true + }, + "yargs": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz", + "integrity": "sha1-wMQpJMpKqmsObaFznfshZDn53cA=", + "dev": true, + "requires": { + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "lodash.assign": "4.2.0", + "os-locale": "1.4.0", + "read-pkg-up": "1.0.1", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "1.0.2", + "which-module": "1.0.0", + "window-size": "0.2.0", + "y18n": "3.2.1", + "yargs-parser": "2.4.1" + } + }, + "yargs-parser": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz", + "integrity": "sha1-hVaN488VD/SfpRgl8DqMiA3cxcQ=", + "dev": true, + "requires": { + "camelcase": "3.0.0", + "lodash.assign": "4.2.0" + } + } + } + }, "cliui": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", @@ -530,6 +1875,35 @@ } } }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + }, + "clone-deep": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.3.0.tgz", + "integrity": "sha1-NIxhrpzb4O3+BT2R/0zFIdeQ7eg=", + "dev": true, + "requires": { + "for-own": "1.0.0", + "is-plain-object": "2.0.4", + "kind-of": "3.2.2", + "shallow-clone": "0.1.2" + }, + "dependencies": { + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "dev": true, + "requires": { + "for-in": "1.0.2" + } + } + } + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -542,6 +1916,22 @@ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", "dev": true }, + "collapse-white-space": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.3.tgz", + "integrity": "sha1-S5BvZw5aljqHt2sOFolkM0G2Ajw=", + "dev": true + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "1.0.0", + "object-visit": "1.0.1" + } + }, "color-convert": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz", @@ -563,26 +1953,99 @@ "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", "dev": true }, + "columnify": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz", + "integrity": "sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs=", + "dev": true, + "requires": { + "strip-ansi": "3.0.1", + "wcwidth": "1.0.1" + } + }, + "combined-stream": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, "commander": { "version": "2.11.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", - "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==" + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true + }, + "common-tags": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.7.2.tgz", + "integrity": "sha512-joj9ZlUOjCrwdbmiLqafeUSgkUM74NqhLsZtSqDmhKudaIY197zTrb8JMl31fMnCUuxwFT23eC/oWvrZzDLRJQ==", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "compress-commons": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-1.2.2.tgz", + "integrity": "sha1-UkqfEJA/OoEzibAiXSfEi7dRiQ8=", + "dev": true, + "requires": { + "buffer-crc32": "0.2.13", + "crc32-stream": "2.0.0", + "normalize-path": "2.1.1", + "readable-stream": "2.3.3" + } }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, "concat-stream": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", + "dev": true, "requires": { "inherits": "2.0.3", "readable-stream": "2.3.3", "typedarray": "0.0.6" } }, + "configstore": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-1.4.0.tgz", + "integrity": "sha1-w1eB0FAdJowlxUuLF/YkDopPsCE=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "mkdirp": "0.5.1", + "object-assign": "4.1.1", + "os-tmpdir": "1.0.2", + "osenv": "0.1.5", + "uuid": "2.0.3", + "write-file-atomic": "1.3.4", + "xdg-basedir": "2.0.0" + }, + "dependencies": { + "uuid": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", + "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=", + "dev": true + } + } + }, "console-browserify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", @@ -598,15 +2061,50 @@ "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", "dev": true }, + "convert-source-map": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", + "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", + "dev": true + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-js": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.4.tgz", + "integrity": "sha1-8si/GB8qgLkvNgEhQpzmOi8K6uA=", + "dev": true + }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true }, - "create-ecdh": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz", - "integrity": "sha1-iIxyNZbN92EvZJgjPuvXo1MBc30=", + "crc": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.5.0.tgz", + "integrity": "sha1-mLi6fUiWZbo5efWbITgTdBAaGWQ=", + "dev": true + }, + "crc32-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-2.0.0.tgz", + "integrity": "sha1-483TtN8xaN10494/u8t7KX/pCPQ=", + "dev": true, + "requires": { + "crc": "3.5.0", + "readable-stream": "2.3.3" + } + }, + "create-ecdh": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz", + "integrity": "sha1-iIxyNZbN92EvZJgjPuvXo1MBc30=", "dev": true, "requires": { "bn.js": "4.11.7", @@ -617,6 +2115,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "dev": true, "requires": { "capture-stack-trace": "1.0.0" } @@ -647,6 +2146,60 @@ "sha.js": "2.4.8" } }, + "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.2", + "shebang-command": "1.2.0", + "which": "1.3.0" + }, + "dependencies": { + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "which": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", + "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "dev": true, + "requires": { + "isexe": "2.0.0" + } + } + } + }, + "crx-parser": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/crx-parser/-/crx-parser-0.1.2.tgz", + "integrity": "sha1-fu7tnt3JXiLBiTguNGJARKiaWm0=", + "dev": true + }, + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "dev": true, + "requires": { + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "dev": true, + "requires": { + "hoek": "4.2.1" + } + } + } + }, "crypto-browserify": { "version": "3.11.1", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.11.1.tgz", @@ -665,6 +2218,30 @@ "randombytes": "2.0.5" } }, + "crypto-random-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", + "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", + "dev": true + }, + "css-select": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", + "dev": true, + "requires": { + "boolbase": "1.0.0", + "css-what": "2.1.0", + "domutils": "1.5.1", + "nth-check": "1.0.1" + } + }, + "css-what": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz", + "integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0=", + "dev": true + }, "d": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", @@ -674,12 +2251,27 @@ "es5-ext": "0.10.24" } }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + } + }, "date-now": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", "dev": true }, + "debounce": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.1.0.tgz", + "integrity": "sha512-ZQVKfRVlwRfD150ndzEK8M90ABT+Y/JQKs4Y7U4MXdpuoUkkrr4DwKbVux3YjylA5bUMUj0Nc3pMxPJX6N2QQQ==", + "dev": true + }, "debug": { "version": "2.6.8", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", @@ -695,6 +2287,18 @@ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", "dev": true }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", + "dev": true + }, "deep-extend": { "version": "0.2.11", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.2.11.tgz", @@ -707,6 +2311,55 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, + "deepcopy": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/deepcopy/-/deepcopy-0.6.3.tgz", + "integrity": "sha1-Y0eA8vhlardxr4+oQx7RzO5Vx7A=", + "dev": true + }, + "deepmerge": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-2.1.0.tgz", + "integrity": "sha512-Q89Z26KAfA3lpPGhbF6XMfYAm3jIV3avViy6KOJ2JLzFbeWHOvPQUu5aSJIWXap3gDZC2y1eF5HXEPI2wGqgvw==", + "dev": true + }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dev": true, + "requires": { + "clone": "1.0.4" + } + }, + "define-properties": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", + "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", + "dev": true, + "requires": { + "foreach": "2.0.5", + "object-keys": "1.0.11" + } + }, + "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" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, "del": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", @@ -722,6 +2375,12 @@ "rimraf": "2.6.1" } }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, "des.js": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", @@ -732,10 +2391,20 @@ "minimalistic-assert": "1.0.0" } }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "requires": { + "repeating": "2.0.1" + } + }, "diff": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", - "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=" + "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", + "dev": true }, "diffie-hellman": { "version": "5.0.2", @@ -748,6 +2417,196 @@ "randombytes": "2.0.5" } }, + "dispensary": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/dispensary/-/dispensary-0.16.0.tgz", + "integrity": "sha1-cXPygoOAE148jrn2Fxn6A4wM0TM=", + "dev": true, + "requires": { + "array-from": "2.1.1", + "async": "2.6.0", + "natural-compare-lite": "1.4.0", + "pino": "4.14.0", + "request": "2.85.0", + "semver": "5.5.0", + "sha.js": "2.4.8", + "source-map-support": "0.5.4", + "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 + }, + "async": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", + "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", + "dev": true, + "requires": { + "lodash": "4.17.4" + } + }, + "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" + }, + "dependencies": { + "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" + } + } + } + }, + "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" + } + }, + "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 + }, + "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" + } + }, + "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.0", + "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" + } + } + } + }, + "doctoc": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/doctoc/-/doctoc-1.3.1.tgz", + "integrity": "sha1-8BLjYD4xViVMLvIqyIxxkPVUJro=", + "dev": true, + "requires": { + "anchor-markdown-header": "0.5.7", + "htmlparser2": "3.9.2", + "markdown-to-ast": "3.4.0", + "minimist": "1.2.0", + "underscore": "1.8.3", + "update-section": "0.3.3" + }, + "dependencies": { + "entities": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", + "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=", + "dev": true + }, + "htmlparser2": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz", + "integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=", + "dev": true, + "requires": { + "domelementtype": "1.3.0", + "domhandler": "2.3.0", + "domutils": "1.5.1", + "entities": "1.1.1", + "inherits": "2.0.3", + "readable-stream": "2.3.3" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, "doctrine": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.0.tgz", @@ -813,14 +2672,78 @@ "domelementtype": "1.3.0" } }, + "dot-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz", + "integrity": "sha1-G3CK8JSknJoOfbyteQq6U52sEXc=", + "dev": true, + "requires": { + "is-obj": "1.0.1" + } + }, + "dtrace-provider": { + "version": "0.8.6", + "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.8.6.tgz", + "integrity": "sha1-QooiOv4DQl0s1tY0f99AxmkDVj0=", + "dev": true, + "optional": true, + "requires": { + "nan": "2.6.2" + } + }, + "duplexer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", + "dev": true + }, "duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "dev": true, "requires": { "readable-stream": "2.3.3" } }, + "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.4", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.4.tgz", + "integrity": "sha512-JzYSLYMhoVVBe8+mbHQ4KgpvHpm0DZpJuL8PY93Vyv1fW7jYJ90LoXa1di/CVbJM+TgMs91rbDapE/RNIfnJsA==", + "dev": true, + "requires": { + "end-of-stream": "1.4.1", + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "stream-shift": "1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.9.tgz", + "integrity": "sha1-S8kmJ07Dtau1AW5+HWCSGsJisqE=", + "dev": true, + "requires": { + "base64url": "2.0.0", + "safe-buffer": "5.1.1" + } + }, "elliptic": { "version": "6.4.0", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", @@ -836,12 +2759,42 @@ "minimalistic-crypto-utils": "1.0.1" } }, + "email-validator": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/email-validator/-/email-validator-1.1.1.tgz", + "integrity": "sha512-vkcJJZEb7JXDY883Nx1Lkmb6noM3j1SfSt8L9tVFhZPnPQiFq+Nkd5evc77+tRVS4ChTUSr34voThsglI/ja/A==", + "dev": true + }, + "emoji-regex": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.1.3.tgz", + "integrity": "sha1-7HmjlpsC0uzytyJUJ5v5m8eoOTI=", + "dev": true + }, "emojis-list": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", "dev": true }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "dev": true, + "requires": { + "iconv-lite": "0.4.18" + } + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "dev": true, + "requires": { + "once": "1.4.0" + } + }, "enhanced-resolve": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-3.3.0.tgz", @@ -873,10 +2826,35 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "dev": true, "requires": { "is-arrayish": "0.2.1" } }, + "es-abstract": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.11.0.tgz", + "integrity": "sha512-ZnQrE/lXTTQ39ulXZ+J1DTFazV9qBy61x2bY071B+qGco8Z8q1QddsLdt/EF8Ai9hcWH72dWS0kFqXLxOxqslA==", + "dev": true, + "requires": { + "es-to-primitive": "1.1.1", + "function-bind": "1.1.1", + "has": "1.0.1", + "is-callable": "1.1.3", + "is-regex": "1.0.4" + } + }, + "es-to-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", + "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", + "dev": true, + "requires": { + "is-callable": "1.1.3", + "is-date-object": "1.0.1", + "is-symbol": "1.0.1" + } + }, "es5-ext": { "version": "0.10.24", "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.24.tgz", @@ -887,7 +2865,13 @@ "es6-symbol": "3.1.1" } }, - "es6-iterator": { + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "es6-iterator": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", "integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=", @@ -912,6 +2896,29 @@ "event-emitter": "0.3.5" } }, + "es6-promise": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-2.3.0.tgz", + "integrity": "sha1-lu258v2wGZWCKyY92KratnSBgbw=", + "dev": true + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "requires": { + "es6-promise": "4.2.4" + }, + "dependencies": { + "es6-promise": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", + "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==", + "dev": true + } + } + }, "es6-set": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", @@ -950,7 +2957,8 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true }, "escope": { "version": "3.6.0", @@ -1042,6 +3050,239 @@ "sax": "1.2.4" } }, + "eslint-plugin-no-unsafe-innerhtml": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/eslint-plugin-no-unsafe-innerhtml/-/eslint-plugin-no-unsafe-innerhtml-1.0.16.tgz", + "integrity": "sha1-fQKHjI6b95FriINtWsEitC8VGTI=", + "dev": true, + "requires": { + "eslint": "3.19.0" + }, + "dependencies": { + "ajv-keywords": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", + "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", + "dev": true + }, + "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" + } + }, + "eslint": { + "version": "3.19.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", + "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", + "dev": true, + "requires": { + "babel-code-frame": "6.22.0", + "chalk": "1.1.3", + "concat-stream": "1.6.0", + "debug": "2.6.8", + "doctrine": "2.0.0", + "escope": "3.6.0", + "espree": "3.4.3", + "esquery": "1.0.0", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "glob": "7.1.2", + "globals": "9.18.0", + "ignore": "3.3.3", + "imurmurhash": "0.1.4", + "inquirer": "0.12.0", + "is-my-json-valid": "2.17.2", + "is-resolvable": "1.0.0", + "js-yaml": "3.9.0", + "json-stable-stringify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "1.2.1", + "progress": "1.1.8", + "require-uncached": "1.0.3", + "shelljs": "0.7.8", + "strip-bom": "3.0.0", + "strip-json-comments": "2.0.1", + "table": "3.8.3", + "text-table": "0.2.0", + "user-home": "2.0.0" + } + }, + "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" + } + }, + "inquirer": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", + "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", + "dev": true, + "requires": { + "ansi-escapes": "1.4.0", + "ansi-regex": "2.1.1", + "chalk": "1.1.3", + "cli-cursor": "1.0.2", + "cli-width": "2.1.0", + "figures": "1.7.0", + "lodash": "4.17.4", + "readline2": "1.0.1", + "run-async": "0.1.0", + "rx-lite": "3.1.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "through": "2.3.8" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "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" + } + }, + "onetime": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "dev": true + }, + "pluralize": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", + "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", + "dev": true + }, + "progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "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" + } + }, + "run-async": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", + "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", + "dev": true, + "requires": { + "once": "1.4.0" + } + }, + "rx-lite": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", + "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=", + "dev": true + }, + "shelljs": { + "version": "0.7.8", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", + "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", + "dev": true, + "requires": { + "glob": "7.1.2", + "interpret": "1.0.3", + "rechoir": "0.6.2" + } + }, + "string-width": { + "version": "1.0.2", + "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", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "table": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", + "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", + "dev": true, + "requires": { + "ajv": "4.11.8", + "ajv-keywords": "1.5.1", + "chalk": "1.1.3", + "lodash": "4.17.4", + "slice-ansi": "0.0.4", + "string-width": "2.1.1" + }, + "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 + }, + "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 + }, + "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" + } + } + } + } + } + }, "eslint-scope": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", @@ -1052,6 +3293,12 @@ "estraverse": "4.2.0" } }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "dev": true + }, "espree": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/espree/-/espree-3.4.3.tgz", @@ -1109,6 +3356,27 @@ "es5-ext": "0.10.24" } }, + "event-stream": { + "version": "3.3.4", + "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", + "dev": true, + "requires": { + "duplexer": "0.1.1", + "from": "0.1.7", + "map-stream": "0.1.0", + "pause-stream": "0.0.11", + "split": "0.3.3", + "stream-combiner": "0.0.4", + "through": "2.3.8" + } + }, + "event-to-promise": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/event-to-promise/-/event-to-promise-0.8.0.tgz", + "integrity": "sha1-S4TxF3K28l93Uvx02XFTGsb1tiY=", + "dev": true + }, "events": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", @@ -1124,12 +3392,33 @@ "create-hash": "1.1.3" } }, + "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" + } + }, "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-brackets": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", @@ -1148,12 +3437,39 @@ "fill-range": "2.2.3" } }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true + }, "extend-object": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/extend-object/-/extend-object-1.0.0.tgz", "integrity": "sha1-QlFPhAFdE1bK9Rh5ad+yvBvaCCM=", "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" + } + } + } + }, "external-editor": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.0.4.tgz", @@ -1174,18 +3490,57 @@ "is-extglob": "1.0.0" } }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, "fast-deep-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=", "dev": true }, + "fast-json-parse": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz", + "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==", + "dev": true + }, + "fast-json-patch": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-1.2.2.tgz", + "integrity": "sha1-03fZfGkR290qHIC/rNoEik+Du/k=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, + "fast-safe-stringify": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-1.2.3.tgz", + "integrity": "sha512-QJYT/i0QYoiZBQ71ivxdyTqkwKkQ0oxACXHYxH2zYHJEgzi2LsbjgvtzTbLi1SZcF190Db2YP7I7eTsU2egOlw==", + "dev": true + }, + "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" + } + }, "figures": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", @@ -1224,6 +3579,12 @@ "repeat-string": "1.6.1" } }, + "filled-array": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/filled-array/-/filled-array-1.1.0.tgz", + "integrity": "sha1-w8T2xmO5I0WamqKZEtLQMfFQf4Q=", + "dev": true + }, "find-up": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", @@ -1234,6 +3595,62 @@ "pinkie-promise": "2.0.1" } }, + "firefox-profile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/firefox-profile/-/firefox-profile-1.1.0.tgz", + "integrity": "sha512-wUIE4QeAjwoHvFbomWmXgKyYtV4/oZxDcJG4znxtGGa/0BhKkd3HzeOf3tAsMWPq1ExARZxCRRiNw1BL3FuPqA==", + "dev": true, + "requires": { + "adm-zip": "0.4.7", + "archiver": "2.1.1", + "async": "2.5.0", + "fs-extra": "4.0.3", + "ini": "1.3.4", + "jetpack-id": "1.0.0", + "lazystream": "1.0.0", + "lodash": "4.17.4", + "minimist": "1.2.0", + "uuid": "3.2.1", + "xml2js": "0.4.17" + }, + "dependencies": { + "fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "4.0.0", + "universalify": "0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "first-chunk-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz", + "integrity": "sha1-G97NuOCDwGZLkZRVgVd6Q6nzHXA=", + "dev": true, + "requires": { + "readable-stream": "2.3.3" + } + }, "fixpack": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/fixpack/-/fixpack-2.3.1.tgz", @@ -1258,6 +3675,18 @@ "write": "0.2.1" } }, + "flatstr": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.5.tgz", + "integrity": "sha1-W0UbCMvUji6sVKK74L9GFlqhS+M=", + "dev": true + }, + "fluent-syntax": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/fluent-syntax/-/fluent-syntax-0.6.6.tgz", + "integrity": "sha512-8iuHPWpn8pPt7/GOBcoDu+x34PkKOH7D0xIjq4C0K2tmf2Bo9bSYVlCj1kvv8g51xKInCyKYg6q5wb6cKZjdUA==", + "dev": true + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -1273,10 +3702,49 @@ "for-in": "1.0.2" } }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.6", + "mime-types": "2.1.18" + } + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "0.2.2" + } + }, + "from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", + "dev": true + }, "fs-extra": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.0.tgz", "integrity": "sha1-QU+0yi0hcLoAFBWdOorsMwNBjZ4=", + "dev": true, "requires": { "graceful-fs": "4.1.11", "jsonfile": "3.0.1", @@ -1286,7 +3754,8 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true }, "fsevents": { "version": "1.1.2", @@ -2057,14 +4526,6 @@ } } }, - "string_decoder": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, "string-width": { "version": "1.0.2", "bundled": true, @@ -2075,6 +4536,14 @@ "strip-ansi": "3.0.1" } }, + "string_decoder": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "requires": { + "safe-buffer": "5.0.1" + } + }, "stringstream": { "version": "0.0.5", "bundled": true, @@ -2191,6 +4660,7 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", + "dev": true, "requires": { "graceful-fs": "4.1.11", "inherits": "2.0.3", @@ -2198,10 +4668,23 @@ "rimraf": "2.6.1" } }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "fx-runner": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/fx-runner/-/fx-runner-1.0.7.tgz", "integrity": "sha1-wQLP3yEjTC29FnI9zLEYb5nAtkE=", + "dev": true, "requires": { "commander": "2.9.0", "lodash": "3.10.1", @@ -2216,6 +4699,7 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, "requires": { "graceful-readlink": "1.0.1" } @@ -2223,7 +4707,8 @@ "lodash": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", - "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", + "dev": true } } }, @@ -2231,6 +4716,7 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/geckodriver/-/geckodriver-1.8.0.tgz", "integrity": "sha1-ef7fk3B3w0uu5ZGim7zxtgLS1hk=", + "dev": true, "requires": { "adm-zip": "0.4.7", "bluebird": "3.4.6", @@ -2238,16 +4724,86 @@ "tar.gz": "1.0.5" } }, - "get-caller-file": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", + "generate-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", + "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", + "dev": true + }, + "generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "dev": true, + "requires": { + "is-property": "1.0.2" + } + }, + "get-caller-file": { + "version": "1.0.2", + "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", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "gettext-parser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/gettext-parser/-/gettext-parser-1.1.0.tgz", + "integrity": "sha1-LFpmONiTk0ubVQN9CtgstwBLJnk=", + "dev": true, + "requires": { + "encoding": "0.1.12" + } + }, + "git-rev-sync": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/git-rev-sync/-/git-rev-sync-1.9.1.tgz", + "integrity": "sha1-oMLj3TkqvPa3aWLif8dfsyI0Sc4=", + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5", + "graceful-fs": "4.1.11", + "shelljs": "0.7.7" + }, + "dependencies": { + "shelljs": { + "version": "0.7.7", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.7.tgz", + "integrity": "sha1-svXHfvlxSPS09uImguELuoZnz/E=", + "dev": true, + "requires": { + "glob": "7.1.2", + "interpret": "1.0.3", + "rechoir": "0.6.2" + } + } + } + }, "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, "requires": { "fs.realpath": "1.0.0", "inflight": "1.0.6", @@ -2276,6 +4832,15 @@ "is-glob": "2.0.1" } }, + "global-dirs": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", + "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "dev": true, + "requires": { + "ini": "1.3.4" + } + }, "globals": { "version": "9.18.0", "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", @@ -2300,6 +4865,7 @@ "version": "5.6.0", "resolved": "https://registry.npmjs.org/got/-/got-5.6.0.tgz", "integrity": "sha1-ux1+4WO3gIK7yOuDbz85UATqb78=", + "dev": true, "requires": { "create-error-class": "3.0.2", "duplexer2": "0.1.4", @@ -2322,17 +4888,74 @@ "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true }, "graceful-readlink": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true + }, + "graphlib": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.5.tgz", + "integrity": "sha512-XvtbqCcw+EM5SqQrIetIKKD+uZVNQtDPD1goIg7K73RuRZtVI5rYMdcCVSHm/AS1sCBZ7vt0p5WgXouucHQaOA==", + "dev": true, + "requires": { + "lodash": "4.17.4" + } }, "growl": { "version": "1.9.2", "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", - "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=" + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "dev": true + }, + "growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "dev": true, + "requires": { + "ajv": "5.5.2", + "har-schema": "2.0.0" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.0.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + } + } + }, + "has": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", + "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", + "dev": true, + "requires": { + "function-bind": "1.1.1" + } }, "has-ansi": { "version": "2.0.0", @@ -2343,12 +4966,95 @@ "ansi-regex": "2.1.1" } }, + "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-flag": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", "dev": true }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "2.0.6", + "has-values": "1.0.0", + "isobject": "3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "3.0.0", + "kind-of": "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" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "hasbin": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/hasbin/-/hasbin-1.2.3.tgz", + "integrity": "sha1-eMWSaJPIAhXCtWiuH9P8q3omlrA=", + "dev": true, + "requires": { + "async": "1.5.2" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + } + } + }, "hash-base": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", @@ -2368,6 +5074,18 @@ "minimalistic-assert": "1.0.0" } }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "dev": true, + "requires": { + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.1", + "sntp": "2.1.0" + } + }, "hmac-drbg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", @@ -2379,6 +5097,22 @@ "minimalistic-crypto-utils": "1.0.1" } }, + "hoek": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", + "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==", + "dev": true + }, + "home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "dev": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, "hosted-git-info": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", @@ -2424,6 +5158,17 @@ } } }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.14.1" + } + }, "https-browserify": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz", @@ -2448,6 +5193,12 @@ "integrity": "sha1-QyNS5XrM2HqzEQ6C0/6g5HgSFW0=", "dev": true }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -2460,10 +5211,17 @@ "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", "dev": true }, + "infinity-agent": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/infinity-agent/-/infinity-agent-2.0.3.tgz", + "integrity": "sha1-ReDi/3qesDCyfWK3SzdEt6esQhY=", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, "requires": { "once": "1.4.0", "wrappy": "1.0.2" @@ -2472,7 +5230,8 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true }, "ini": { "version": "1.3.4", @@ -2560,6 +5319,15 @@ "integrity": "sha1-y8NcYu7uc/Gat7EKgBURQBr8D5A=", "dev": true }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "1.3.1" + } + }, "invert-kv": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", @@ -2570,14 +5338,49 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz", "integrity": "sha1-hHSREZ/MtftDYhfMc39/qtUPYD8=", + "dev": true, "requires": { "is-relative": "0.1.3" } }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "6.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "is-alphabetical": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.1.tgz", + "integrity": "sha1-x3B5zJHU76x3W+EDS/LSQ/lebwg=", + "dev": true + }, + "is-alphanumerical": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.1.tgz", + "integrity": "sha1-37SqTRCF4zvbYcLe6cgOnGwZ9Ts=", + "dev": true, + "requires": { + "is-alphabetical": "1.0.1", + "is-decimal": "1.0.1" + } + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true }, "is-binary-path": { "version": "1.0.1", @@ -2603,6 +5406,60 @@ "builtin-modules": "1.1.1" } }, + "is-callable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz", + "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=", + "dev": true + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "6.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-decimal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.1.tgz", + "integrity": "sha1-9ftqlJlq2ejjdh+/vQkfH8qMToI=", + "dev": true + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "1.0.0", + "is-data-descriptor": "1.0.0", + "kind-of": "6.0.2" + }, + "dependencies": { + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, "is-dotfile": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", @@ -2630,6 +5487,15 @@ "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", "dev": true }, + "is-finite": { + "version": "1.0.2", + "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" + } + }, "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", @@ -2645,43 +5511,131 @@ "is-extglob": "1.0.0" } }, - "is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "is-hexadecimal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.1.tgz", + "integrity": "sha1-bghLvJIGH7sJcexYts5tQE4k2mk=", + "dev": true + }, + "is-installed-globally": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", + "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", "dev": true, "requires": { - "kind-of": "3.2.2" + "global-dirs": "0.1.1", + "is-path-inside": "1.0.0" } }, - "is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "is-mergeable-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-mergeable-object/-/is-mergeable-object-1.1.0.tgz", + "integrity": "sha512-JfyDDwUdtS4yHCgUpxOyKB9dnfZ0gecufxB0eytX6BmSXSE+8dbxDGt+V7CNRIRJ9sYFV/WQt2KJG6hNob2sBw==", "dev": true }, - "is-path-in-cwd": { + "is-my-ip-valid": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", - "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", + "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", + "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", + "dev": true + }, + "is-my-json-valid": { + "version": "2.17.2", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz", + "integrity": "sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg==", "dev": true, "requires": { - "is-path-inside": "1.0.0" + "generate-function": "2.0.0", + "generate-object-property": "1.2.0", + "is-my-ip-valid": "1.0.0", + "jsonpointer": "4.0.1", + "xtend": "4.0.1" } }, - "is-path-inside": { + "is-npm": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", - "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", + "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=", + "dev": true + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", "dev": true, "requires": { - "path-is-inside": "1.0.2" + "kind-of": "3.2.2" } }, - "is-plain-obj": { - "version": "1.1.0", + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + }, + "is-odd": { + "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": "4.0.0" + }, + "dependencies": { + "is-number": { + "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 + } + } + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", + "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", + "dev": true, + "requires": { + "is-path-inside": "1.0.0" + } + }, + "is-path-inside": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", + "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", + "dev": true, + "requires": { + "path-is-inside": "1.0.2" + } + }, + "is-plain-obj": { + "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } }, "is-posix-bracket": { "version": "0.1.1", @@ -2701,15 +5655,32 @@ "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", "dev": true }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "dev": true + }, "is-redirect": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", - "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=" + "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", + "dev": true + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "1.0.1" + } }, "is-relative": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz", - "integrity": "sha1-kF/uiuhvRbPsYUvDwVyGnfCHboI=" + "integrity": "sha1-kF/uiuhvRbPsYUvDwVyGnfCHboI=", + "dev": true }, "is-resolvable": { "version": "1.0.0", @@ -2723,12 +5694,26 @@ "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=" + "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=", + "dev": true }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", + "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true }, "is-utf8": { "version": "0.2.1", @@ -2736,15 +5721,29 @@ "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", "dev": true }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isemail": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/isemail/-/isemail-1.2.0.tgz", + "integrity": "sha1-vgPfjMPineTSxd9lASY/H6RZXpo=", + "dev": true }, "isexe": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/isexe/-/isexe-1.1.2.tgz", - "integrity": "sha1-NvPiLmB1CSD15yQaR2qMakInWtA=" + "integrity": "sha1-NvPiLmB1CSD15yQaR2qMakInWtA=", + "dev": true }, "isobject": { "version": "2.1.0", @@ -2755,6 +5754,62 @@ "isarray": "1.0.0" } }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "jed": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/jed/-/jed-1.1.1.tgz", + "integrity": "sha1-elSbvZ/+FYWwzQoZHiAwVb7ldLQ=", + "dev": true + }, + "jetpack-id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jetpack-id/-/jetpack-id-1.0.0.tgz", + "integrity": "sha1-LPn7rkbYB0/Ba33gBxyO/rykc6Y=", + "dev": true + }, + "joi": { + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/joi/-/joi-6.10.1.tgz", + "integrity": "sha1-TVDDGAeRIgAP5fFq8f+OGRe3fgY=", + "dev": true, + "requires": { + "hoek": "2.16.3", + "isemail": "1.2.0", + "moment": "2.22.0", + "topo": "1.1.0" + }, + "dependencies": { + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "dev": true + } + } + }, + "js-select": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/js-select/-/js-select-0.6.0.tgz", + "integrity": "sha1-woTiKCTVknrsli3N8kcXSu+w0ZA=", + "dev": true, + "requires": { + "JSONSelect": "0.2.1", + "traverse": "0.4.6" + }, + "dependencies": { + "traverse": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.4.6.tgz", + "integrity": "sha1-0EsigOTHkqWBVCnve4tgxkyczDQ=", + "dev": true + } + } + }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -2771,12 +5826,25 @@ "esprima": "4.0.0" } }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, "jschardet": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/jschardet/-/jschardet-1.4.2.tgz", "integrity": "sha1-KqEH8UKvQSHRRWWdRPUIMJYeaZo=", "dev": true }, + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true + }, "jshint": { "version": "2.9.5", "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.5.tgz", @@ -2813,6 +5881,27 @@ "integrity": "sha1-i6oTZaYy9Yo8RtIBdfxgAsluN94=", "dev": true }, + "json-merge-patch": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-merge-patch/-/json-merge-patch-0.2.3.tgz", + "integrity": "sha1-+ixrWvh9p3uuKWalidUuI+2B/kA=", + "dev": true, + "requires": { + "deep-equal": "1.0.1" + } + }, + "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-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, "json-schema-traverse": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", @@ -2828,10 +5917,23 @@ "jsonify": "0.0.0" } }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, "json3": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", - "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=" + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true }, "json5": { "version": "0.5.1", @@ -2843,6 +5945,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", + "dev": true, "requires": { "graceful-fs": "4.1.11" } @@ -2850,7 +5953,87 @@ "jsonify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, + "jsonpointer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", + "dev": true + }, + "jsonwebtoken": { + "version": "7.1.9", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-7.1.9.tgz", + "integrity": "sha1-hHgE5SWL7FqUmajcSl56O64I1Yo=", + "dev": true, + "requires": { + "joi": "6.10.1", + "jws": "3.1.4", + "lodash.once": "4.1.1", + "ms": "0.7.3", + "xtend": "4.0.1" + }, + "dependencies": { + "ms": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.3.tgz", + "integrity": "sha1-cIFVpeROM/X9D8U+gdDUCpG+H/8=", + "dev": true + } + } + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "jszip": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-2.6.1.tgz", + "integrity": "sha1-uI86ey5noqBIFSmCx6N1bZxIKPA=", + "dev": true, + "requires": { + "pako": "1.0.6" + }, + "dependencies": { + "pako": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", + "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==", + "dev": true + } + } + }, + "jwa": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.5.tgz", + "integrity": "sha1-oFUs4CIHQs1S4VN3SjKQXDDnVuU=", + "dev": true, + "requires": { + "base64url": "2.0.0", + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.9", + "safe-buffer": "5.1.1" + } + }, + "jws": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.1.4.tgz", + "integrity": "sha1-+ei5M46KhHJ31kRLFGT2GIDgUKI=", + "dev": true, + "requires": { + "base64url": "2.0.0", + "jwa": "1.1.5", + "safe-buffer": "5.1.1" + } }, "kind-of": { "version": "3.2.2", @@ -2861,12 +6044,30 @@ "is-buffer": "1.1.5" } }, + "latest-version": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-2.0.0.tgz", + "integrity": "sha1-VvjWE5YghHuAF/jx9NeOIRMkFos=", + "dev": true, + "requires": { + "package-json": "2.4.0" + } + }, "lazy-cache": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", "dev": true }, + "lazystream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", + "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", + "dev": true, + "requires": { + "readable-stream": "2.3.3" + } + }, "lcid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", @@ -2917,15 +6118,35 @@ "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", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true }, "lodash._baseassign": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", + "dev": true, "requires": { "lodash._basecopy": "3.0.1", "lodash.keys": "3.1.2" @@ -2934,105 +6155,267 @@ "lodash._basecopy": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=" + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true }, "lodash._basecreate": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", - "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=" + "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", + "dev": true }, "lodash._getnative": { "version": "3.9.1", "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=" + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true }, "lodash._isiterateecall": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=" + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "dev": true + }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true }, "lodash.create": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", + "dev": true, "requires": { "lodash._baseassign": "3.2.0", "lodash._basecreate": "3.0.3", "lodash._isiterateecall": "3.0.9" } }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=", + "dev": true + }, + "lodash.defaultsdeep": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.0.tgz", + "integrity": "sha1-vsECT4WxvZbL6kBbI8FK1kQ6b4E=", + "dev": true + }, "lodash.isarguments": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=" + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "dev": true }, "lodash.isarray": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=" + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true }, "lodash.keys": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, "requires": { "lodash._getnative": "3.9.1", "lodash.isarguments": "3.1.0", "lodash.isarray": "3.0.4" } }, + "lodash.mergewith": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz", + "integrity": "sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==", + "dev": true + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=", + "dev": true + }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true + }, "longest": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", "dev": true }, - "lowercase-keys": { + "longest-streak": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", - "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=" + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-1.0.0.tgz", + "integrity": "sha1-0GWXxNTDG1LMsfXY+P5xSOr9aWU=", + "dev": true }, - "memory-fs": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", - "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "loose-envify": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", + "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", "dev": true, "requires": { - "errno": "0.1.4", - "readable-stream": "2.3.3" + "js-tokens": "3.0.2" } }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "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 + }, + "lru-cache": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.2.tgz", + "integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==", "dev": true, "requires": { - "arr-diff": "2.0.0", - "array-unique": "0.2.1", - "braces": "1.8.5", - "expand-brackets": "0.1.5", - "extglob": "0.3.2", - "filename-regex": "2.0.1", - "is-extglob": "1.0.0", - "is-glob": "2.0.1", - "kind-of": "3.2.2", - "normalize-path": "2.1.1", - "object.omit": "2.0.1", - "parse-glob": "3.0.4", - "regex-cache": "0.4.3" + "pseudomap": "1.0.2", + "yallist": "2.1.2" } }, - "miller-rabin": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.0.tgz", - "integrity": "sha1-SmL7HUKTPAVYOYL0xxb2+55sbT0=", + "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": { - "bn.js": "4.11.7", + "pify": "3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-stream": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", + "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "1.0.1" + } + }, + "markdown-table": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-0.4.0.tgz", + "integrity": "sha1-iQwsGzv+g/sA5BKbjkz+ZFJw+dE=", + "dev": true + }, + "markdown-to-ast": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/markdown-to-ast/-/markdown-to-ast-3.4.0.tgz", + "integrity": "sha1-Diy6gTkLBUmpFT7DsNkVthwWS+c=", + "dev": true, + "requires": { + "debug": "2.6.8", + "remark": "5.1.0", + "structured-source": "3.0.2", + "traverse": "0.6.6" + } + }, + "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" + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "0.1.4", + "readable-stream": "2.3.3" + } + }, + "memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", + "dev": true + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "2.0.0", + "array-unique": "0.2.1", + "braces": "1.8.5", + "expand-brackets": "0.1.5", + "extglob": "0.3.2", + "filename-regex": "2.0.1", + "is-extglob": "1.0.0", + "is-glob": "2.0.1", + "kind-of": "3.2.2", + "normalize-path": "2.1.1", + "object.omit": "2.0.1", + "parse-glob": "3.0.4", + "regex-cache": "0.4.3" + } + }, + "miller-rabin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.0.tgz", + "integrity": "sha1-SmL7HUKTPAVYOYL0xxb2+55sbT0=", + "dev": true, + "requires": { + "bn.js": "4.11.7", "brorand": "1.1.0" } }, + "mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "dev": true + }, + "mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "dev": true, + "requires": { + "mime-db": "1.33.0" + } + }, "mimic-fn": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", @@ -3055,6 +6438,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, "requires": { "brace-expansion": "1.1.8" } @@ -3062,12 +6446,53 @@ "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mixin-deep": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", + "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "dev": true, + "requires": { + "for-in": "1.0.2", + "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" + } + } + } + }, + "mixin-object": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", + "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", + "dev": true, + "requires": { + "for-in": "0.1.8", + "is-extendable": "0.1.1" + }, + "dependencies": { + "for-in": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", + "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=", + "dev": true + } + } }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, "requires": { "minimist": "0.0.8" } @@ -3076,6 +6501,7 @@ "version": "3.4.2", "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.4.2.tgz", "integrity": "sha1-0O9NMyEm2/GNDWQMmzgt1IvpdZQ=", + "dev": true, "requires": { "browser-stdout": "1.3.0", "commander": "2.9.0", @@ -3094,6 +6520,7 @@ "version": "2.9.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, "requires": { "graceful-readlink": "1.0.1" } @@ -3102,6 +6529,7 @@ "version": "2.6.0", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.0.tgz", "integrity": "sha1-vFlryr52F/Edn6FTYe3tVgi4SZs=", + "dev": true, "requires": { "ms": "0.7.2" } @@ -3110,6 +6538,7 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "dev": true, "requires": { "fs.realpath": "1.0.0", "inflight": "1.0.6", @@ -3122,27 +6551,37 @@ "has-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=" + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true }, "ms": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz", - "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=" + "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=", + "dev": true }, "supports-color": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", + "dev": true, "requires": { "has-flag": "1.0.0" } } } }, + "moment": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.0.tgz", + "integrity": "sha512-1muXCh8jb1N/gHRbn9VDUBr0GYb8A/aVcHlII9QSB68a50spqEVLIGN6KVmCOnSvJrUhC0edGgKU5ofnGXdYdg==", + "dev": true + }, "mout": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/mout/-/mout-0.11.1.tgz", - "integrity": "sha1-ujYR318OWx/7/QEWa48C0fX6K5k=" + "integrity": "sha1-ujYR318OWx/7/QEWa48C0fX6K5k=", + "dev": true }, "ms": { "version": "2.0.0", @@ -3156,6 +6595,55 @@ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", "dev": true }, + "mv": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz", + "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=", + "dev": true, + "optional": true, + "requires": { + "mkdirp": "0.5.1", + "ncp": "2.0.0", + "rimraf": "2.4.5" + }, + "dependencies": { + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "dev": true, + "optional": true, + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "rimraf": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz", + "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=", + "dev": true, + "optional": true, + "requires": { + "glob": "6.0.4" + } + } + } + }, + "mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "requires": { + "any-promise": "1.3.0", + "object-assign": "4.1.1", + "thenify-all": "1.6.0" + } + }, "nan": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/nan/-/nan-2.6.2.tgz", @@ -3163,12 +6651,140 @@ "dev": true, "optional": true }, + "nanomatch": { + "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": "2.0.2", + "extend-shallow": "3.0.2", + "fragment-cache": "0.2.1", + "is-odd": "2.0.0", + "is-windows": "1.0.2", + "kind-of": "6.0.2", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha1-F7CVgZiJef3a/gIB6TG6kzyWy7Q=", + "dev": true + }, + "nconf": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/nconf/-/nconf-0.7.2.tgz", + "integrity": "sha1-oF/fItwBw3jdXE3yfy3JC5qouwA=", + "dev": true, + "requires": { + "async": "0.9.2", + "ini": "1.3.4", + "yargs": "3.15.0" + }, + "dependencies": { + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", + "dev": true + }, + "window-size": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", + "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=", + "dev": true + }, + "yargs": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.15.0.tgz", + "integrity": "sha1-PZRG7yH7N5GzmFaQZi5LloPH8YE=", + "dev": true, + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.4" + } + } + } + }, + "ncp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", + "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=", + "dev": true, + "optional": true + }, + "needle": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.0.tgz", + "integrity": "sha512-eFagy6c+TYayorXw/qtAdSvaUpEbBsDwDyxYFgLZ0lTojfH7K+OdBqAF7TAFwDokJaGpubpSGG0wO3iC0XPi8w==", + "dev": true, + "requires": { + "debug": "2.6.8", + "iconv-lite": "0.4.18", + "sax": "1.2.4" + } + }, + "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 + }, + "nested-error-stacks": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-1.0.2.tgz", + "integrity": "sha1-GfYZWRUZ8JZ2mlupqG5u7sgjw88=", + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "node-forge": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz", + "integrity": "sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ==", + "dev": true + }, "node-libs-browser": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.0.0.tgz", @@ -3208,10 +6824,87 @@ } } }, + "node-notifier": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.2.1.tgz", + "integrity": "sha512-MIBs+AAd6dJ2SklbbE8RUDRlIVhU8MaNLh1A9SUZDUHPiZkWLFde6UNwG41yQHZEToHgJMXqyVZ9UcS/ReOVTg==", + "dev": true, + "requires": { + "growly": "1.3.0", + "semver": "5.5.0", + "shellwords": "0.1.1", + "which": "1.3.0" + }, + "dependencies": { + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + }, + "which": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", + "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "dev": true, + "requires": { + "isexe": "2.0.0" + } + } + } + }, "node-status-codes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-status-codes/-/node-status-codes-1.0.0.tgz", - "integrity": "sha1-WuVUHQJGRdMqWPzdyc7s6nrjrC8=" + "integrity": "sha1-WuVUHQJGRdMqWPzdyc7s6nrjrC8=", + "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" + }, + "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 + }, + "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" + } + }, + "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 + } + } }, "normalize-package-data": { "version": "2.4.0", @@ -3234,16 +6927,231 @@ "remove-trailing-separator": "1.0.2" } }, - "number-is-nan": { - "version": "1.0.1", - "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", + "npm-run-all": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.2.tgz", + "integrity": "sha512-Z2aRlajMK4SQ8u19ZA75NZZu7wupfCNQWdYosIi8S6FgBdGf/8Y6Hgyjdc8zU2cYmIRVCx1nM80tJPkdEd+UYg==", + "dev": true, + "requires": { + "ansi-styles": "3.2.1", + "chalk": "2.3.2", + "cross-spawn": "5.1.0", + "memorystream": "0.3.1", + "minimatch": "3.0.4", + "ps-tree": "1.1.0", + "read-pkg": "3.0.0", + "shell-quote": "1.6.1", + "string.prototype.padend": "3.0.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==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "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" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "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" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "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" + } + }, + "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" + } + } + } + }, + "npm-run-path": { + "version": "2.0.2", + "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" + } + }, + "nth-check": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz", + "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", + "dev": true, + "requires": { + "boolbase": "1.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "0.1.1", + "define-property": "0.2.5", + "kind-of": "3.2.2" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "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 + } + } + } + } + }, + "object-keys": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", + "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } }, "object.omit": { "version": "2.0.1", @@ -3255,10 +7163,28 @@ "is-extendable": "0.1.1" } }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, "requires": { "wrappy": "1.0.2" } @@ -3272,6 +7198,12 @@ "mimic-fn": "1.1.0" } }, + "open": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/open/-/open-0.0.5.tgz", + "integrity": "sha1-QsPhjslUZra/DcQvOilFw/DK2Pw=", + "dev": true + }, "optionator": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", @@ -3292,6 +7224,12 @@ "integrity": "sha1-Y/xMzuXS13Y9Jrv4YBB45sLgBE8=", "dev": true }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, "os-locale": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", @@ -3301,15 +7239,96 @@ "lcid": "1.0.0" } }, + "os-name": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-1.0.3.tgz", + "integrity": "sha1-GzefZINa98Wn9JizV8uVIVwVnt8=", + "dev": true, + "requires": { + "osx-release": "1.1.0", + "win-release": "1.1.1" + } + }, "os-shim": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz", - "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=" + "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=", + "dev": true }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "osx-release": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/osx-release/-/osx-release-1.1.0.tgz", + "integrity": "sha1-8heRGigTaUmvG/kwiyQeJzfTzWw=", + "dev": true, + "requires": { + "minimist": "1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "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-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-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 + }, + "package-json": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-2.4.0.tgz", + "integrity": "sha1-DRW9Z9HLvduyyiIv8u24a8sxqLs=", + "dev": true, + "requires": { + "got": "5.6.0", + "registry-auth-token": "3.3.2", + "registry-url": "3.1.0", + "semver": "5.3.0" + } }, "pako": { "version": "0.2.9", @@ -3330,6 +7349,20 @@ "pbkdf2": "3.0.12" } }, + "parse-entities": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-1.1.1.tgz", + "integrity": "sha1-gRLYhHExnyerrk1klksSL+ThuJA=", + "dev": true, + "requires": { + "character-entities": "1.2.1", + "character-entities-legacy": "1.1.1", + "character-reference-invalid": "1.1.1", + "is-alphanumerical": "1.0.1", + "is-decimal": "1.0.1", + "is-hexadecimal": "1.0.1" + } + }, "parse-glob": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", @@ -3346,25 +7379,38 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, "requires": { "error-ex": "1.3.1" } }, - "path": { - "version": "0.12.7", - "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", - "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=", + "parse5": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz", + "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==", + "dev": true, "requires": { - "process": "0.11.10", - "util": "0.10.3" + "@types/node": "9.6.1" } }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, "path-browserify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", "dev": true }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, "path-exists": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", @@ -3377,7 +7423,8 @@ "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true }, "path-is-inside": { "version": "1.0.2", @@ -3385,6 +7432,18 @@ "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", "dev": true }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.5", + "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", "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", @@ -3396,6 +7455,15 @@ "pinkie-promise": "2.0.1" } }, + "pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", + "dev": true, + "requires": { + "through": "2.3.8" + } + }, "pbkdf2": { "version": "3.0.12", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.12.tgz", @@ -3409,6 +7477,18 @@ "sha.js": "2.4.8" } }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, "pify": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", @@ -3418,32 +7498,164 @@ "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true }, "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, "requires": { "pinkie": "2.0.4" } }, + "pino": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-4.14.0.tgz", + "integrity": "sha512-nuPTxdy3OHmsdZmi8hzZYlW0m2+8HLUYM8euys6OOKVGBRF8TY7uFGvQZMLkwNgG+Zw+pNaGUw7OIMa76Ok2eg==", + "dev": true, + "requires": { + "chalk": "2.3.2", + "fast-json-parse": "1.0.3", + "fast-safe-stringify": "1.2.3", + "flatstr": "1.0.5", + "pino-std-serializers": "1.2.0", + "pump": "3.0.0", + "quick-format-unescaped": "1.1.2", + "split2": "2.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==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "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" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "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" + } + } + } + }, + "pino-std-serializers": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-1.2.0.tgz", + "integrity": "sha512-6LQcMXLHlT+PKMFkY6WpPmQvkFIecngF7WJPiMi5PfCGcScikvB3kt+Q5+zLtxw0dxPqXHd9XczPx/HwsNmOIA==", + "dev": true + }, "pluralize": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-4.0.0.tgz", "integrity": "sha1-WbcIwcAZCi9pLxx2GMRGsFL9F2I=", "dev": true }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "po2json": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/po2json/-/po2json-0.4.5.tgz", + "integrity": "sha1-R7spUtoy1Yob4vJWpZjuvAt0URg=", + "dev": true, + "requires": { + "gettext-parser": "1.1.0", + "nomnom": "1.8.1" + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "postcss": { + "version": "6.0.19", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.19.tgz", + "integrity": "sha512-f13HRz0HtVwVaEuW6J6cOUCBLFtymhgyLPV7t4QEk2UD3twRI9IluDcQNdzQdBpiixkXj2OmzejhhTbSbDxNTg==", + "dev": true, + "requires": { + "chalk": "2.3.2", + "source-map": "0.6.1", + "supports-color": "5.3.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==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "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" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "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 + }, + "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" + } + } + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", "dev": true }, "prepend-http": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true }, "preserve": { "version": "0.2.0", @@ -3451,15 +7663,43 @@ "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", "dev": true }, + "prettier": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.11.1.tgz", + "integrity": "sha512-T/KD65Ot0PB97xTrG8afQ46x3oiVhnfGjGESSI9NWYcG92+OUPZKkwHqGWXH2t9jK1crnQjubECW0FuOth+hxw==", + "dev": true + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, + "probe-image-size": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/probe-image-size/-/probe-image-size-4.0.0.tgz", + "integrity": "sha512-nm7RvWUxps+2+jZKNLkd04mNapXNariS6G5WIEVzvAqjx7EUuKcY1Dp3e6oUK7GLwzJ+3gbSbPLFAASHFQrPcQ==", + "dev": true, + "requires": { + "any-promise": "1.3.0", + "deepmerge": "2.1.0", + "inherits": "2.0.3", + "next-tick": "1.0.0", + "request": "2.85.0", + "stream-parser": "0.3.1" + } + }, "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true }, "process-nextick-args": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true }, "progress": { "version": "2.0.0", @@ -3467,12 +7707,42 @@ "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", "dev": true }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "requires": { + "asap": "2.0.6" + } + }, + "proxy-from-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=", + "dev": true + }, "prr": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz", "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=", "dev": true }, + "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", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, "public-encrypt": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz", @@ -3486,12 +7756,28 @@ "randombytes": "2.0.5" } }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "1.4.1", + "once": "1.4.0" + } + }, "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", "dev": true }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", + "dev": true + }, "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", @@ -3504,6 +7790,15 @@ "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", "dev": true }, + "quick-format-unescaped": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-1.1.2.tgz", + "integrity": "sha1-DKWB3jF0vs7yWsPC6JVjQjgdtpg=", + "dev": true, + "requires": { + "fast-safe-stringify": "1.2.3" + } + }, "randomatic": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", @@ -3578,6 +7873,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz", "integrity": "sha1-NcPhd/IHjveJ7kv6+kNzB06u9Po=", + "dev": true, "requires": { "pinkie-promise": "2.0.1", "readable-stream": "2.3.3" @@ -3608,6 +7904,7 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, "requires": { "core-util-is": "1.0.2", "inherits": "2.0.3", @@ -3630,6 +7927,58 @@ "set-immediate-shim": "1.0.1" } }, + "readline2": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", + "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "mute-stream": "0.0.5" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "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" + } + }, + "mute-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", + "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", + "dev": true + } + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "1.6.0" + } + }, + "recursive-readdir": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/recursive-readdir/-/recursive-readdir-2.2.2.tgz", + "integrity": "sha512-nRCcW9Sj7NuZwa2XvH9co8NPeXUBhZP7CRKJtU+cS6PW9FpCIFoI5ib0NT1ZrbNuPoRy0ylyCaUL8Gih4LSyFg==", + "dev": true, + "requires": { + "minimatch": "3.0.4" + } + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==", + "dev": true + }, "regex-cache": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz", @@ -3640,6 +7989,147 @@ "is-primitive": "2.0.0" } }, + "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" + } + }, + "regexpp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", + "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", + "dev": true + }, + "registry-auth-token": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.2.tgz", + "integrity": "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==", + "dev": true, + "requires": { + "rc": "1.2.6", + "safe-buffer": "5.1.1" + }, + "dependencies": { + "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 + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "rc": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.6.tgz", + "integrity": "sha1-6xiYnG1PTxYsOZ953dKfODVWgJI=", + "dev": true, + "requires": { + "deep-extend": "0.4.2", + "ini": "1.3.4", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + } + } + } + }, + "registry-url": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", + "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", + "dev": true, + "requires": { + "rc": "1.2.6" + }, + "dependencies": { + "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 + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "rc": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.6.tgz", + "integrity": "sha1-6xiYnG1PTxYsOZ953dKfODVWgJI=", + "dev": true, + "requires": { + "deep-extend": "0.4.2", + "ini": "1.3.4", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + } + } + } + }, + "relaxed-json": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/relaxed-json/-/relaxed-json-1.0.1.tgz", + "integrity": "sha1-fI1KovCVcEzQIOMugJm8rhA/C9Q=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "commander": "2.11.0" + } + }, + "remark": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/remark/-/remark-5.1.0.tgz", + "integrity": "sha1-y0Y709vLS5l5STXu4c9x16jjBow=", + "dev": true, + "requires": { + "remark-parse": "1.1.0", + "remark-stringify": "1.1.0", + "unified": "4.2.1" + } + }, + "remark-parse": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-1.1.0.tgz", + "integrity": "sha1-w8oQ+ajaBGFcKPCapOMEUQUm7CE=", + "dev": true, + "requires": { + "collapse-white-space": "1.0.3", + "extend": "3.0.1", + "parse-entities": "1.1.1", + "repeat-string": "1.6.1", + "trim": "0.0.1", + "trim-trailing-lines": "1.1.0", + "unherit": "1.1.0", + "unist-util-remove-position": "1.1.1", + "vfile-location": "2.0.2" + } + }, + "remark-stringify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-1.1.0.tgz", + "integrity": "sha1-pxBeJbnuK/mkm3XSxCPxGwauIJI=", + "dev": true, + "requires": { + "ccount": "1.0.2", + "extend": "3.0.1", + "longest-streak": "1.0.0", + "markdown-table": "0.4.0", + "parse-entities": "1.1.1", + "repeat-string": "1.6.1", + "stringify-entities": "1.3.1", + "unherit": "1.1.0" + } + }, "remove-trailing-separator": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz", @@ -3658,6 +8148,45 @@ "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", "dev": true }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "1.0.2" + } + }, + "request": { + "version": "2.85.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz", + "integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==", + "dev": true, + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.6", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.2", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.18", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.4", + "tunnel-agent": "0.6.0", + "uuid": "3.2.1" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -3680,12 +8209,27 @@ "resolve-from": "1.0.1" } }, + "resolve": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.6.0.tgz", + "integrity": "sha512-mw7JQNu5ExIkcw4LPih0owX/TZXjD/ZUF/ZQ/pDnkw3ZKhDcZZw5klmBlj6gVMwjQ3Pz5Jgu7F3d0jcDVuEWdw==", + "dev": true, + "requires": { + "path-parse": "1.0.5" + } + }, "resolve-from": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", "dev": true }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", @@ -3696,6 +8240,12 @@ "signal-exit": "3.0.2" } }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, "right-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", @@ -3709,6 +8259,7 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz", "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=", + "dev": true, "requires": { "glob": "7.1.2" } @@ -3732,6 +8283,12 @@ "is-promise": "2.1.0" } }, + "rx": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", + "integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=", + "dev": true + }, "rx-lite": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", @@ -3750,17 +8307,36 @@ "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "safe-json-stringify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.1.0.tgz", + "integrity": "sha512-EzBtUaFH9bHYPc69wqjp0efJI/DPNHdFbGE3uIMn4sVbO0zx8vZ8cG4WKxQfOpUOKsQyGBiT2mTqnCw+6nLswA==", + "dev": true, + "optional": true + }, + "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" + } }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true }, "selenium-webdriver": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.4.0.tgz", "integrity": "sha1-FR90RSlNpqZsScwwB0eioX5TxSo=", + "dev": true, "requires": { "adm-zip": "0.4.7", "rimraf": "2.6.1", @@ -3772,6 +8348,7 @@ "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" } @@ -3784,6 +8361,15 @@ "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", "dev": true }, + "semver-diff": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", + "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", + "dev": true, + "requires": { + "semver": "5.3.0" + } + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -3796,6 +8382,29 @@ "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", "dev": true }, + "set-value": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", + "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "dev": true, + "requires": { + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "split-string": "3.1.0" + }, + "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" + } + } + } + }, "setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", @@ -3811,28 +8420,278 @@ "inherits": "2.0.3" } }, - "shell-quote": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", - "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", + "shallow-clone": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz", + "integrity": "sha1-WQnodLp3EG1zrEFM/sH/yofZcGA=", + "dev": true, "requires": { - "array-filter": "0.0.1", - "array-map": "0.0.0", - "array-reduce": "0.0.0", - "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 - }, + "is-extendable": "0.1.1", + "kind-of": "2.0.1", + "lazy-cache": "0.2.7", + "mixin-object": "2.0.1" + }, + "dependencies": { + "kind-of": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", + "integrity": "sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + }, + "lazy-cache": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.7.tgz", + "integrity": "sha1-f+3fLctu23fRHvHRF6tf/fCrG2U=", + "dev": true + } + } + }, + "shebang-command": { + "version": "1.2.0", + "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" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "shell-quote": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", + "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", + "dev": true, + "requires": { + "array-filter": "0.0.1", + "array-map": "0.0.0", + "array-reduce": "0.0.0", + "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", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "dev": true + }, "shield-study-schemas": { "version": "0.8.3", "resolved": "https://registry.npmjs.org/shield-study-schemas/-/shield-study-schemas-0.8.3.tgz", - "integrity": "sha1-2yBiSamGlJkVnThHxxiYV1lfgM0=", - "dev": true + "integrity": "sha1-2yBiSamGlJkVnThHxxiYV1lfgM0=" + }, + "sign-addon": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/sign-addon/-/sign-addon-0.3.0.tgz", + "integrity": "sha512-xc9beD51s4OUaBIstN9xXfZMzEVqi9iYXbrOTDivxb3Z6+nSw/X4q6tXqqJ+QP0kyMzQxLTagnRroC5wWVH5mQ==", + "dev": true, + "requires": { + "babel-polyfill": "6.16.0", + "deepcopy": "0.6.3", + "es6-error": "4.0.0", + "es6-promisify": "5.0.0", + "jsonwebtoken": "7.1.9", + "mz": "2.5.0", + "request": "2.79.0", + "source-map-support": "0.4.6", + "stream-to-promise": "2.2.0", + "when": "3.7.7" + }, + "dependencies": { + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", + "dev": true + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", + "dev": true + }, + "babel-polyfill": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.16.0.tgz", + "integrity": "sha1-LUUCHfh+JqN0ttTRqcZZZNF/JCI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "core-js": "2.5.4", + "regenerator-runtime": "0.9.6" + } + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "caseless": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", + "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", + "dev": true + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "dev": true, + "requires": { + "boom": "2.10.1" + } + }, + "es6-error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.0.0.tgz", + "integrity": "sha1-8JTHBB9mJZm7EnINoFnWucf/D0A=", + "dev": true + }, + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.6", + "mime-types": "2.1.18" + } + }, + "har-validator": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", + "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "commander": "2.11.0", + "is-my-json-valid": "2.17.2", + "pinkie-promise": "2.0.1" + } + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "dev": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "dev": true + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "dev": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.1", + "sshpk": "1.14.1" + } + }, + "mz": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.5.0.tgz", + "integrity": "sha1-KFkCXfA9RrV7sxcXSxlkd85kzsE=", + "dev": true, + "requires": { + "any-promise": "1.3.0", + "object-assign": "4.1.1", + "thenify-all": "1.6.0" + } + }, + "qs": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz", + "integrity": "sha1-51vV9uJoEioqDgvaYwslUMFmUCw=", + "dev": true + }, + "regenerator-runtime": { + "version": "0.9.6", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.9.6.tgz", + "integrity": "sha1-0z65XQ0gAaS+OWWXB8UbDLcc4Ck=", + "dev": true + }, + "request": { + "version": "2.79.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", + "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", + "dev": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.11.0", + "combined-stream": "1.0.6", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "2.0.6", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.18", + "oauth-sign": "0.8.2", + "qs": "6.3.2", + "stringstream": "0.0.5", + "tough-cookie": "2.3.4", + "tunnel-agent": "0.4.3", + "uuid": "3.2.1" + } + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "source-map-support": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.6.tgz", + "integrity": "sha1-MlUqpktFg5KoXqs7C17mFScWeus=", + "dev": true, + "requires": { + "source-map": "0.5.6" + } + }, + "tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", + "dev": true + } + } }, "signal-exit": { "version": "3.0.2", @@ -3840,99 +8699,1597 @@ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", "dev": true }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, "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 }, - "source-list-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", - "integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==", + "slide": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "0.11.2", + "debug": "2.6.8", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "map-cache": "0.2.2", + "source-map": "0.5.6", + "source-map-resolve": "0.5.1", + "use": "3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "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-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "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 + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "1.0.0", + "isobject": "3.0.1", + "snapdragon-util": "3.0.1" + }, + "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" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "sntp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", + "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", + "dev": true, + "requires": { + "hoek": "4.2.1" + } + }, + "snyk": { + "version": "1.70.3", + "resolved": "https://registry.npmjs.org/snyk/-/snyk-1.70.3.tgz", + "integrity": "sha1-U8mJSdJ79XkF7re+7ZTTYKJP/1U=", + "dev": true, + "requires": { + "abbrev": "1.1.1", + "ansi-escapes": "1.4.0", + "chalk": "1.1.3", + "configstore": "1.4.0", + "debug": "3.1.0", + "es6-promise": "3.3.1", + "hasbin": "1.2.3", + "inquirer": "1.0.3", + "needle": "2.2.0", + "open": "0.0.5", + "os-name": "1.0.3", + "proxy-from-env": "1.0.0", + "recursive-readdir": "2.2.2", + "semver": "5.3.0", + "snyk-config": "1.0.1", + "snyk-go-plugin": "1.4.5", + "snyk-gradle-plugin": "1.2.0", + "snyk-module": "1.8.1", + "snyk-mvn-plugin": "1.1.1", + "snyk-nuget-plugin": "1.3.9", + "snyk-php-plugin": "1.3.2", + "snyk-policy": "1.10.2", + "snyk-python-plugin": "1.5.7", + "snyk-resolve": "1.0.0", + "snyk-resolve-deps": "1.7.0", + "snyk-sbt-plugin": "1.2.5", + "snyk-tree": "1.0.0", + "snyk-try-require": "1.2.0", + "tempfile": "1.1.1", + "then-fs": "2.0.0", + "undefsafe": "0.0.3", + "update-notifier": "0.5.0", + "url": "0.11.0", + "uuid": "3.2.1" + }, + "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" + } + }, + "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" + } + }, + "es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=", + "dev": true + }, + "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" + } + }, + "got": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/got/-/got-3.3.1.tgz", + "integrity": "sha1-5dDtSvVfw+701WAHdp2YGSvLLso=", + "dev": true, + "requires": { + "duplexify": "3.5.4", + "infinity-agent": "2.0.3", + "is-redirect": "1.0.0", + "is-stream": "1.1.0", + "lowercase-keys": "1.0.0", + "nested-error-stacks": "1.0.2", + "object-assign": "3.0.0", + "prepend-http": "1.0.4", + "read-all-stream": "3.1.0", + "timed-out": "2.0.0" + }, + "dependencies": { + "object-assign": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", + "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", + "dev": true + } + } + }, + "inquirer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-1.0.3.tgz", + "integrity": "sha1-6+OglIVxvMRszMvi+bzsJR6YS9A=", + "dev": true, + "requires": { + "ansi-escapes": "1.4.0", + "chalk": "1.1.3", + "cli-cursor": "1.0.2", + "cli-width": "2.1.0", + "figures": "1.7.0", + "lodash": "4.17.4", + "mute-stream": "0.0.6", + "pinkie-promise": "2.0.1", + "run-async": "2.3.0", + "rx": "4.1.0", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "through": "2.3.8" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "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" + } + }, + "latest-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-1.0.1.tgz", + "integrity": "sha1-cs/Ebj6NG+ZR4eu1Tqn26pbzdLs=", + "dev": true, + "requires": { + "package-json": "1.2.0" + } + }, + "mute-stream": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.6.tgz", + "integrity": "sha1-SJYrGeFp/R38JAs/HnMXYnu8R9s=", + "dev": true + }, + "onetime": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", + "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", + "dev": true + }, + "package-json": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-1.2.0.tgz", + "integrity": "sha1-yOysCUInzfdqMWh07QXifMk5oOA=", + "dev": true, + "requires": { + "got": "3.3.1", + "registry-url": "3.1.0" + } + }, + "repeating": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz", + "integrity": "sha1-PUEUIYh3U3SU+X93+Xhfq4EPpKw=", + "dev": true, + "requires": { + "is-finite": "1.0.2" + } + }, + "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" + } + }, + "string-width": { + "version": "1.0.2", + "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", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "update-notifier": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-0.5.0.tgz", + "integrity": "sha1-B7XcIGazYnqztPUwEw9+3doHpMw=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "configstore": "1.4.0", + "is-npm": "1.0.0", + "latest-version": "1.0.1", + "repeating": "1.1.3", + "semver-diff": "2.1.0", + "string-length": "1.0.1" + } + } + } + }, + "snyk-config": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/snyk-config/-/snyk-config-1.0.1.tgz", + "integrity": "sha1-8nrsJJiyQCescZIUAmUhWRERUI8=", + "dev": true, + "requires": { + "debug": "2.6.8", + "nconf": "0.7.2", + "path-is-absolute": "1.0.1" + } + }, + "snyk-go-plugin": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/snyk-go-plugin/-/snyk-go-plugin-1.4.5.tgz", + "integrity": "sha512-uuPXt/NDROmG/pnQveOdur/ToG3h4W64F8r+3L7ZCMPikkRkieoCMGpfMYhEgG+oMlO1bzAsf+YGvMfY0o96Kg==", + "dev": true, + "requires": { + "graphlib": "2.1.5", + "toml": "2.3.3" + } + }, + "snyk-gradle-plugin": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/snyk-gradle-plugin/-/snyk-gradle-plugin-1.2.0.tgz", + "integrity": "sha512-FucMRR+Rc6LBaSIYxiBl+jvb7R00SgA0QfMT+RGxLIZlDk1lagvA/jIkv+mRadwHVSV/ShIFSZLmS7agfPclVg==", + "dev": true, + "requires": { + "clone-deep": "0.3.0" + } + }, + "snyk-module": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/snyk-module/-/snyk-module-1.8.1.tgz", + "integrity": "sha1-MdUID7HA39b6hWfdNKUj/QK/H8o=", + "dev": true, + "requires": { + "debug": "2.6.8", + "hosted-git-info": "2.5.0" + } + }, + "snyk-mvn-plugin": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/snyk-mvn-plugin/-/snyk-mvn-plugin-1.1.1.tgz", + "integrity": "sha512-CkOAkOYVpEXm/c0peKNpEhbSIqb6SxNM28L5Rt5XZOkZ00Ud3uhz26+AicZVgvhe3in8A2CzOIAPyMUL2ueW4A==", + "dev": true + }, + "snyk-nuget-plugin": { + "version": "1.3.9", + "resolved": "https://registry.npmjs.org/snyk-nuget-plugin/-/snyk-nuget-plugin-1.3.9.tgz", + "integrity": "sha512-F38Amr8AxbalFfUmjLM+57P2Gq2vUh9dWsP7oE2DPXO/f7tW00jwyWhJ5D39Zx+elBoXDxWYvAp14IJnxV18Ag==", + "dev": true, + "requires": { + "debug": "3.1.0", + "es6-promise": "4.2.4", + "xml2js": "0.4.17", + "zip": "1.2.0" + }, + "dependencies": { + "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" + } + }, + "es6-promise": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", + "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==", + "dev": true + } + } + }, + "snyk-php-plugin": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/snyk-php-plugin/-/snyk-php-plugin-1.3.2.tgz", + "integrity": "sha512-EVN5ilP2PJ5EEBWUvSjzI1kHTRyJxqCQXm5Bb2Kkl4z1cNCFO9ScxjwUDO7cJmQCDQUhHGflDd611ToWmlEYnQ==", + "dev": true, + "requires": { + "debug": "3.1.0" + }, + "dependencies": { + "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" + } + } + } + }, + "snyk-policy": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/snyk-policy/-/snyk-policy-1.10.2.tgz", + "integrity": "sha1-Knvw8Hx7gRud2pPPm7sQ3Jkt17w=", + "dev": true, + "requires": { + "debug": "2.6.8", + "email-validator": "1.1.1", + "es6-promise": "3.3.1", + "js-yaml": "3.9.0", + "lodash.clonedeep": "4.5.0", + "semver": "5.3.0", + "snyk-module": "1.8.1", + "snyk-resolve": "1.0.0", + "snyk-try-require": "1.2.0", + "then-fs": "2.0.0" + }, + "dependencies": { + "es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=", + "dev": true + } + } + }, + "snyk-python-plugin": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/snyk-python-plugin/-/snyk-python-plugin-1.5.7.tgz", + "integrity": "sha512-+BJ0ORdZSt62fIxDKkOi7TmKC9sFE9B4QXpoZV7Y0OtScEN99HYT7h4Jh3Hs8c9Vu40UmGfLQG1r78PoqxmM3Q==", + "dev": true + }, + "snyk-resolve": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/snyk-resolve/-/snyk-resolve-1.0.0.tgz", + "integrity": "sha1-u+kZbTf1fDklHmvnXM3Vsgl+maI=", + "dev": true, + "requires": { + "debug": "2.6.8", + "then-fs": "2.0.0" + } + }, + "snyk-resolve-deps": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/snyk-resolve-deps/-/snyk-resolve-deps-1.7.0.tgz", + "integrity": "sha1-E3Q6BYQ33/iQuq9DfDM8lmp0PLY=", + "dev": true, + "requires": { + "abbrev": "1.1.1", + "ansicolors": "0.3.2", + "clite": "0.3.0", + "debug": "2.6.8", + "es6-promise": "3.3.1", + "lodash": "4.17.4", + "lru-cache": "4.1.2", + "minimist": "1.2.0", + "semver": "5.3.0", + "snyk-module": "1.8.1", + "snyk-resolve": "1.0.0", + "snyk-tree": "1.0.0", + "snyk-try-require": "1.2.0", + "then-fs": "2.0.0" + }, + "dependencies": { + "es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=", + "dev": true + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "snyk-sbt-plugin": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/snyk-sbt-plugin/-/snyk-sbt-plugin-1.2.5.tgz", + "integrity": "sha512-6D981zAdFYatBLNwp7J5Vl5wZFieBlwKj1Ans9uZ5BZZfg4mjIX/62tfADmJEbHijvnN+i7N8cNQRvVOyLo2UA==", + "dev": true, + "requires": { + "debug": "2.6.8" + } + }, + "snyk-tree": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/snyk-tree/-/snyk-tree-1.0.0.tgz", + "integrity": "sha1-D7cxdtvzLngvGRAClBYESPkRHMg=", + "dev": true, + "requires": { + "archy": "1.0.0" + } + }, + "snyk-try-require": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/snyk-try-require/-/snyk-try-require-1.2.0.tgz", + "integrity": "sha1-MPwrEcBwZFke41eAyCa+kTEvIUQ=", + "dev": true, + "requires": { + "debug": "2.6.8", + "es6-promise": "3.3.1", + "lodash.clonedeep": "4.5.0", + "lru-cache": "4.1.2", + "then-fs": "2.0.0" + }, + "dependencies": { + "es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=", + "dev": true + } + } + }, + "source-list-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", + "integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==", + "dev": true + }, + "source-map": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", + "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.1.tgz", + "integrity": "sha512-0KW2wvzfxm8NCTb30z0LMNyPqWCdDGE2viwzUaucqJdkTRXtZiSY3I+2A6nVAjmdOy0I4gU8DwnVVGsk9jvP2A==", + "dev": true, + "requires": { + "atob": "2.1.0", + "decode-uri-component": "0.2.0", + "resolve-url": "0.2.1", + "source-map-url": "0.4.0", + "urix": "0.1.0" + } + }, + "source-map-support": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.3.tgz", + "integrity": "sha512-eKkTgWYeBOQqFGXRfKabMFdnWepo51vWqEdoeikaEPFiJC7MCU5j2h4+6Q8npkZTeLGbSyecZvRxiSoWl3rh+w==", + "dev": true, + "requires": { + "source-map": "0.6.1" + }, + "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-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "spawn-sync": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", + "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=", + "dev": true, + "requires": { + "concat-stream": "1.6.0", + "os-shim": "0.1.3" + } + }, + "spdx-correct": { + "version": "1.0.2", + "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" + } + }, + "spdx-expression-parse": { + "version": "1.0.4", + "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", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", + "dev": true + }, + "split": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", + "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", + "dev": true, + "requires": { + "through": "2.3.8" + } + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "3.0.2" + } + }, + "split2": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-2.2.0.tgz", + "integrity": "sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw==", + "dev": true, + "requires": { + "through2": "2.0.3" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz", + "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=", + "dev": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "0.2.5", + "object-copy": "0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "0.1.6" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "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 + } + } + }, + "stream-browserify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", + "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3" + } + }, + "stream-combiner": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", + "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", + "dev": true, + "requires": { + "duplexer": "0.1.1" + } + }, + "stream-http": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.7.2.tgz", + "integrity": "sha512-c0yTD2rbQzXtSsFSVhtpvY/vS6u066PcXOX9kBB3mSO76RiUQzL340uJkGBWnlBg4/HZzqiUXtaVA7wcRcJgEw==", + "dev": true, + "requires": { + "builtin-status-codes": "3.0.0", + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "to-arraybuffer": "1.0.1", + "xtend": "4.0.1" + } + }, + "stream-parser": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/stream-parser/-/stream-parser-0.3.1.tgz", + "integrity": "sha1-FhhUhpRCACGhGC/wrxkRwSl2F3M=", + "dev": true, + "requires": { + "debug": "2.6.8" + } + }, + "stream-shift": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "dev": true + }, + "stream-to-array": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/stream-to-array/-/stream-to-array-2.3.0.tgz", + "integrity": "sha1-u/azn19D7DC8cbq8s3VXrOzzQ1M=", + "dev": true, + "requires": { + "any-promise": "1.3.0" + } + }, + "stream-to-promise": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/stream-to-promise/-/stream-to-promise-2.2.0.tgz", + "integrity": "sha1-se2y4cjLESidG1A8CNPyrvUeZQ8=", + "dev": true, + "requires": { + "any-promise": "1.3.0", + "end-of-stream": "1.1.0", + "stream-to-array": "2.3.0" + }, + "dependencies": { + "end-of-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.1.0.tgz", + "integrity": "sha1-6TUyWLqpEIll78QcsO+K3i88+wc=", + "dev": true, + "requires": { + "once": "1.3.3" + } + }, + "once": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", + "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + } + } + }, + "string-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz", + "integrity": "sha1-VpcPscOFWOnnC3KL894mmsRa36w=", + "dev": true, + "requires": { + "strip-ansi": "3.0.1" + } + }, + "string-width": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.0.tgz", + "integrity": "sha1-AwZkVh/BRslCPsfZeP4kV0N/5tA=", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.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 + }, + "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" + } + } + } + }, + "string.prototype.padend": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz", + "integrity": "sha1-86rvfBcZ8XDF6rHDK/eA2W4h8vA=", + "dev": true, + "requires": { + "define-properties": "1.1.2", + "es-abstract": "1.11.0", + "function-bind": "1.1.1" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "stringify-entities": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-1.3.1.tgz", + "integrity": "sha1-sVDsLXKsTBtfMktR+2soyc3/BYw=", + "dev": true, + "requires": { + "character-entities-html4": "1.1.1", + "character-entities-legacy": "1.1.1", + "is-alphanumerical": "1.0.1", + "is-hexadecimal": "1.0.1" + } + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "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" + } + }, + "strip-bom": { + "version": "2.0.0", + "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" + } + }, + "strip-bom-buf": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-buf/-/strip-bom-buf-1.0.0.tgz", + "integrity": "sha1-HLRar1dTD0yvhsf3UXnSyaUd1XI=", + "dev": true, + "requires": { + "is-utf8": "0.2.1" + } + }, + "strip-bom-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-3.0.0.tgz", + "integrity": "sha1-lWvMXYRDD2klapDtgjdlzYWOFZw=", + "dev": true, + "requires": { + "first-chunk-stream": "2.0.0", + "strip-bom-buf": "1.0.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "structured-source": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/structured-source/-/structured-source-3.0.2.tgz", + "integrity": "sha1-3YAkJeD1PcSm56yjdSkBoczaevU=", + "dev": true, + "requires": { + "boundary": "1.0.1" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "table": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.1.tgz", + "integrity": "sha1-qBFsEz+sLGH0pCCrbN9cTWHw5DU=", + "dev": true, + "requires": { + "ajv": "4.11.8", + "ajv-keywords": "1.5.1", + "chalk": "1.1.3", + "lodash": "4.17.4", + "slice-ansi": "0.0.4", + "string-width": "2.1.0" + }, + "dependencies": { + "ajv-keywords": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", + "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", + "dev": true + } + } + }, + "tapable": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.6.tgz", + "integrity": "sha1-IGvo4YiGC1FEJTdebxrom/sB/Y0=", + "dev": true + }, + "tar": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "dev": true, + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" + } + }, + "tar-stream": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.5.tgz", + "integrity": "sha512-mQdgLPc/Vjfr3VWqWbfxW8yQNiJCbAZ+Gf6GDu1Cy0bdb33ofyiNGBtAY96jHFhDuivCwgW1H9DgTON+INiXgg==", + "dev": true, + "requires": { + "bl": "1.2.2", + "end-of-stream": "1.4.1", + "readable-stream": "2.3.3", + "xtend": "4.0.1" + } + }, + "tar.gz": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tar.gz/-/tar.gz-1.0.5.tgz", + "integrity": "sha1-4a2n5F7yJBtLHuWBI8j0C108G8Q=", + "dev": true, + "requires": { + "bluebird": "2.11.0", + "commander": "2.11.0", + "fstream": "1.0.11", + "mout": "0.11.1", + "tar": "2.2.1" + }, + "dependencies": { + "bluebird": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", + "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=", + "dev": true + } + } + }, + "tempfile": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tempfile/-/tempfile-1.1.1.tgz", + "integrity": "sha1-W8xOrsxKsscH2LwR2ZzMmiyyh/I=", + "dev": true, + "requires": { + "os-tmpdir": "1.0.2", + "uuid": "2.0.3" + }, + "dependencies": { + "uuid": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", + "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=", + "dev": true + } + } + }, + "term-size": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", + "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", + "dev": true, + "requires": { + "execa": "0.7.0" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "then-fs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/then-fs/-/then-fs-2.0.0.tgz", + "integrity": "sha1-cveS3Z0xcFqRrhnr/Piz+WjIHaI=", + "dev": true, + "requires": { + "promise": "7.3.1" + } + }, + "thenify": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz", + "integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=", + "dev": true, + "requires": { + "any-promise": "1.3.0" + } + }, + "thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", + "dev": true, + "requires": { + "thenify": "3.3.0" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "through2": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "dev": true, + "requires": { + "readable-stream": "2.3.3", + "xtend": "4.0.1" + } + }, + "timed-out": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz", + "integrity": "sha1-84sK6B03R9YoAB9B2vxlKs5nHAo=", + "dev": true + }, + "timers-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.2.tgz", + "integrity": "sha1-q0iDz1l9zVCvIRNJoA+8pWrIa4Y=", + "dev": true, + "requires": { + "setimmediate": "1.0.5" + } + }, + "tmp": { + "version": "0.0.31", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz", + "integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=", + "dev": true, + "requires": { + "os-tmpdir": "1.0.2" + } + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "3.2.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" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "3.0.0", + "repeat-string": "1.6.1" + }, + "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" + } + } + } + }, + "to-utf8": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/to-utf8/-/to-utf8-0.0.1.tgz", + "integrity": "sha1-0Xrqcv8vujm55DYBvns/9y4ImFI=", + "dev": true + }, + "toml": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/toml/-/toml-2.3.3.tgz", + "integrity": "sha512-O7L5hhSQHxuufWUdcTRPfuTh3phKfAZ/dqfxZFoxPCj2RYmpaSGLEIs016FCXItQwNr08yefUB5TSjzRYnajTA==", + "dev": true + }, + "topo": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/topo/-/topo-1.1.0.tgz", + "integrity": "sha1-6ddRYV0buH3IZdsYL6HKCl71NtU=", + "dev": true, + "requires": { + "hoek": "2.16.3" + }, + "dependencies": { + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "dev": true + } + } + }, + "tosource": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/tosource/-/tosource-1.0.0.tgz", + "integrity": "sha1-QtiN0RZhi88A1hBt1URvNCeQL/E=", + "dev": true + }, + "tough-cookie": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "dev": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dev": true, + "requires": { + "punycode": "2.1.0" + }, + "dependencies": { + "punycode": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", + "integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0=", + "dev": true + } + } + }, + "traverse": { + "version": "0.6.6", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", + "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=", + "dev": true + }, + "trim": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz", + "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=", + "dev": true + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "trim-trailing-lines": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.0.tgz", + "integrity": "sha1-eu+7eAjfnWafbaLkOMrIxGradoQ=", + "dev": true + }, + "trough": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.1.tgz", + "integrity": "sha1-qf2LA5Swro//guBjOgo2zK1bX4Y=", + "dev": true + }, + "tryit": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz", + "integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics=", + "dev": true + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "requires": { + "source-map": "0.5.6", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + }, + "dependencies": { + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + } + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true, + "optional": true + }, + "undefsafe": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-0.0.3.tgz", + "integrity": "sha1-7Mo6A+VrmvFzhbqsgSrIO5lKli8=", "dev": true }, - "source-map": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz", - "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=", + "underscore": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=", "dev": true }, - "spawn-sync": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", - "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=", + "unherit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.0.tgz", + "integrity": "sha1-a5qu379z3xdWrZ4xbdmBiFhAzX0=", + "dev": true, "requires": { - "concat-stream": "1.6.0", - "os-shim": "0.1.3" + "inherits": "2.0.3", + "xtend": "4.0.1" } }, - "spdx-correct": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", - "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", + "unified": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/unified/-/unified-4.2.1.tgz", + "integrity": "sha1-dv9Dqo2kMPbn5KVchOusKtLPzS4=", "dev": true, "requires": { - "spdx-license-ids": "1.2.2" + "bail": "1.0.2", + "extend": "3.0.1", + "has": "1.0.1", + "once": "1.4.0", + "trough": "1.0.1", + "vfile": "1.4.0" } }, - "spdx-expression-parse": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", - "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", - "dev": true + "union-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", + "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "dev": true, + "requires": { + "arr-union": "3.1.0", + "get-value": "2.0.6", + "is-extendable": "0.1.1", + "set-value": "0.4.3" + }, + "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" + } + }, + "set-value": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", + "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "dev": true, + "requires": { + "extend-shallow": "2.0.1", + "is-extendable": "0.1.1", + "is-plain-object": "2.0.4", + "to-object-path": "0.3.0" + } + } + } }, - "spdx-license-ids": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", - "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", - "dev": true + "unique-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", + "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "dev": true, + "requires": { + "crypto-random-string": "1.0.0" + } }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "unist-util-is": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-2.1.1.tgz", + "integrity": "sha1-DDEmKeP5YMZukx6BLT2A53AQlHs=", "dev": true }, - "stream-browserify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", - "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", + "unist-util-remove-position": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-1.1.1.tgz", + "integrity": "sha1-WoXBVV/BugwQG4ZwfRXlD6TIcbs=", "dev": true, "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.3" + "unist-util-visit": "1.3.0" } }, - "stream-http": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.7.2.tgz", - "integrity": "sha512-c0yTD2rbQzXtSsFSVhtpvY/vS6u066PcXOX9kBB3mSO76RiUQzL340uJkGBWnlBg4/HZzqiUXtaVA7wcRcJgEw==", + "unist-util-visit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.3.0.tgz", + "integrity": "sha512-9ntYcxPFtl44gnwXrQKZ5bMqXMY0ZHzUpqMFiU4zcc8mmf/jzYm8GhYgezuUlX4cJIM1zIDYaO6fG/fI+L6iiQ==", "dev": true, "requires": { - "builtin-status-codes": "3.0.0", - "inherits": "2.0.3", - "readable-stream": "2.3.3", - "to-arraybuffer": "1.0.1", - "xtend": "4.0.1" + "unist-util-is": "2.1.1" } }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "requires": { - "safe-buffer": "5.1.1" - } + "universalify": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.0.tgz", + "integrity": "sha1-nrHEZR3rzGcMyU8adXYjMruWd3g=", + "dev": true }, - "string-width": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.0.tgz", - "integrity": "sha1-AwZkVh/BRslCPsfZeP4kV0N/5tA=", + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "dev": true, "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" + "has-value": "0.3.1", + "isobject": "3.0.1" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "2.0.6", + "has-values": "0.1.4", + "isobject": "2.1.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "unzip-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-1.0.2.tgz", + "integrity": "sha1-uYTwh3/AqJwsdzzB73tbIytbBv4=", + "dev": true + }, + "upath": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.0.4.tgz", + "integrity": "sha512-d4SJySNBXDaQp+DPrziv3xGS6w3d2Xt69FijJr86zMPBy23JEloMCEOUBBzuN7xCtjLCnmB9tI/z7SBCahHBOw==", + "dev": true + }, + "update-notifier": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.3.0.tgz", + "integrity": "sha1-TognpruRUUCrCTVZ1wFOPruDdFE=", + "dev": true, + "requires": { + "boxen": "1.3.0", + "chalk": "2.3.2", + "configstore": "3.1.2", + "import-lazy": "2.1.0", + "is-installed-globally": "0.1.0", + "is-npm": "1.0.0", + "latest-version": "3.1.0", + "semver-diff": "2.1.0", + "xdg-basedir": "3.0.0" }, "dependencies": { "ansi-regex": { @@ -3941,6 +10298,116 @@ "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.0" + } + }, + "boxen": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", + "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", + "dev": true, + "requires": { + "ansi-align": "2.0.0", + "camelcase": "4.1.0", + "chalk": "2.3.2", + "cli-boxes": "1.0.0", + "string-width": "2.1.0", + "term-size": "1.2.0", + "widest-line": "2.0.0" + } + }, + "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" + } + }, + "configstore": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", + "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", + "dev": true, + "requires": { + "dot-prop": "4.2.0", + "graceful-fs": "4.1.11", + "make-dir": "1.2.0", + "unique-string": "1.0.0", + "write-file-atomic": "2.3.0", + "xdg-basedir": "3.0.0" + } + }, + "dot-prop": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", + "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "dev": true, + "requires": { + "is-obj": "1.0.1" + } + }, + "got": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", + "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", + "dev": true, + "requires": { + "create-error-class": "3.0.2", + "duplexer3": "0.1.4", + "get-stream": "3.0.0", + "is-redirect": "1.0.0", + "is-retry-allowed": "1.1.0", + "is-stream": "1.1.0", + "lowercase-keys": "1.0.0", + "safe-buffer": "5.1.1", + "timed-out": "4.0.1", + "unzip-response": "2.0.1", + "url-parse-lax": "1.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 + }, + "latest-version": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", + "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", + "dev": true, + "requires": { + "package-json": "4.0.1" + } + }, + "package-json": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", + "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", + "dev": true, + "requires": { + "got": "6.7.1", + "registry-auth-token": "3.3.2", + "registry-url": "3.1.0", + "semver": "5.3.0" + } + }, "strip-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", @@ -3949,280 +10416,669 @@ "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" + } + }, + "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 + }, + "unzip-response": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", + "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", + "dev": true + }, + "widest-line": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.0.tgz", + "integrity": "sha1-AUKk6KJD+IgsAjOqDgKBqnYVInM=", + "dev": true, + "requires": { + "string-width": "2.1.1" + }, + "dependencies": { + "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" + } + } + } + }, + "write-file-atomic": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz", + "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "imurmurhash": "0.1.4", + "signal-exit": "3.0.2" + } + }, + "xdg-basedir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", + "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", + "dev": true } } }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "update-section": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/update-section/-/update-section-0.3.3.tgz", + "integrity": "sha1-RY8Xgg03gg3GDiC4bZQ5GwASMVg=", + "dev": true + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", "dev": true, "requires": { - "ansi-regex": "2.1.1" + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } } }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "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": { - "is-utf8": "0.2.1" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - }, - "table": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/table/-/table-4.0.1.tgz", - "integrity": "sha1-qBFsEz+sLGH0pCCrbN9cTWHw5DU=", + "prepend-http": "1.0.4" + } + }, + "use": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz", + "integrity": "sha512-6UJEQM/L+mzC3ZJNM56Q4DFGLX/evKGRg15UJHGB9X5j5Z3AFbgZvjUh2yq/UJUY4U5dh7Fal++XbNg1uzpRAw==", "dev": true, "requires": { - "ajv": "4.11.8", - "ajv-keywords": "1.5.1", - "chalk": "1.1.3", - "lodash": "4.17.4", - "slice-ansi": "0.0.4", - "string-width": "2.1.0" + "kind-of": "6.0.2" }, "dependencies": { - "ajv-keywords": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", - "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", "dev": true } } }, - "tapable": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.6.tgz", - "integrity": "sha1-IGvo4YiGC1FEJTdebxrom/sB/Y0=", - "dev": true - }, - "tar": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", - "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "user-home": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", + "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", + "dev": true, "requires": { - "block-stream": "0.0.9", - "fstream": "1.0.11", - "inherits": "2.0.3" + "os-homedir": "1.0.2" } }, - "tar.gz": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tar.gz/-/tar.gz-1.0.5.tgz", - "integrity": "sha1-4a2n5F7yJBtLHuWBI8j0C108G8Q=", + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, "requires": { - "bluebird": "2.11.0", - "commander": "2.11.0", - "fstream": "1.0.11", - "mout": "0.11.1", - "tar": "2.2.1" + "inherits": "2.0.1" }, "dependencies": { - "bluebird": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", - "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true } } }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "uuid": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", + "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==", "dev": true }, - "timed-out": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-2.0.0.tgz", - "integrity": "sha1-84sK6B03R9YoAB9B2vxlKs5nHAo=" - }, - "timers-browserify": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.2.tgz", - "integrity": "sha1-q0iDz1l9zVCvIRNJoA+8pWrIa4Y=", + "validate-npm-package-license": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", "dev": true, "requires": { - "setimmediate": "1.0.5" + "spdx-correct": "1.0.2", + "spdx-expression-parse": "1.0.4" } }, - "tmp": { - "version": "0.0.31", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.31.tgz", - "integrity": "sha1-jzirlDjhcxXl29izZX6L+yd65Kc=", + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "dev": true, "requires": { - "os-tmpdir": "1.0.2" + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" } }, - "to-arraybuffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", - "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", - "dev": true - }, - "tryit": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz", - "integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics=", + "vfile": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-1.4.0.tgz", + "integrity": "sha1-wP1vpIT43r23cfaMMe112I2pf+c=", "dev": true }, - "tty-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", - "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "vfile-location": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-2.0.2.tgz", + "integrity": "sha1-02dcWch3SY5JK0dW/2Xkrxp1IlU=", "dev": true }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "vm-browserify": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", + "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", "dev": true, "requires": { - "prelude-ls": "1.1.2" + "indexof": "0.0.1" } }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "watchpack": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.3.1.tgz", + "integrity": "sha1-fYaTkHsozmAT5/NhCqKhrPB9rYc=", "dev": true, "requires": { - "source-map": "0.5.6", - "uglify-to-browserify": "1.0.2", - "yargs": "3.10.0" + "async": "2.5.0", + "chokidar": "1.7.0", + "graceful-fs": "4.1.11" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dev": true, + "requires": { + "defaults": "1.0.3" + } + }, + "web-ext": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/web-ext/-/web-ext-2.6.0.tgz", + "integrity": "sha1-UsB0Ej5jdqT7Zz5WXDPdAncU6bA=", + "dev": true, + "requires": { + "@cliqz-oss/firefox-client": "0.3.1", + "@cliqz-oss/node-firefox-connect": "1.2.1", + "adbkit": "2.11.0", + "addons-linter": "0.41.0", + "babel-polyfill": "6.26.0", + "babel-runtime": "6.26.0", + "bunyan": "1.8.12", + "camelcase": "4.1.0", + "debounce": "1.1.0", + "decamelize": "2.0.0", + "es6-error": "4.1.1", + "es6-promisify": "5.0.0", + "event-to-promise": "0.8.0", + "firefox-profile": "1.1.0", + "fx-runner": "1.0.8", + "git-rev-sync": "1.9.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "mz": "2.7.0", + "node-notifier": "5.2.1", + "open": "0.0.5", + "parse-json": "4.0.0", + "regenerator-runtime": "0.11.1", + "require-uncached": "1.0.3", + "sign-addon": "0.3.0", + "source-map-support": "0.5.3", + "stream-to-promise": "2.2.0", + "strip-json-comments": "2.0.1", + "tmp": "0.0.33", + "update-notifier": "2.3.0", + "watchpack": "1.5.0", + "yargs": "6.6.0", + "zip-dir": "1.0.2" }, "dependencies": { - "yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "3.1.10", + "normalize-path": "2.1.1" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "braces": { + "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", + "array-unique": "0.3.2", + "define-property": "1.0.0", + "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.2", + "snapdragon-node": "2.1.1", + "split-string": "3.1.0", + "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" + } + } + } + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "chokidar": { + "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.1", + "fsevents": "1.1.2", + "glob-parent": "3.1.0", + "inherits": "2.0.3", + "is-binary-path": "1.0.1", + "is-glob": "4.0.0", + "normalize-path": "2.1.1", + "path-is-absolute": "1.0.1", + "readdirp": "2.1.0", + "upath": "1.0.4" + } + }, + "commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "requires": { + "graceful-readlink": "1.0.1" + } + }, + "decamelize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-2.0.0.tgz", + "integrity": "sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg==", + "dev": true, + "requires": { + "xregexp": "4.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "2.6.8", + "define-property": "0.2.5", + "extend-shallow": "2.0.1", + "posix-character-classes": "0.1.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "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 + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "0.3.2", + "define-property": "1.0.0", + "expand-brackets": "2.1.4", + "extend-shallow": "2.0.1", + "fragment-cache": "0.2.1", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "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": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "2.0.1", + "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" + } + } + } + }, + "fx-runner": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/fx-runner/-/fx-runner-1.0.8.tgz", + "integrity": "sha1-XO07BKjVHWNN4g0UgPDcXdgyXew=", + "dev": true, + "requires": { + "commander": "2.9.0", + "lodash": "3.10.1", + "shell-quote": "1.6.1", + "spawn-sync": "1.0.15", + "when": "3.7.7", + "which": "1.2.4", + "winreg": "0.0.12" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "3.1.0", + "path-dirname": "1.0.2" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "2.1.1" + } + } + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", "dev": true, "requires": { - "camelcase": "1.2.1", - "cliui": "2.1.0", - "decamelize": "1.2.0", - "window-size": "0.1.0" + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } } - } - } - }, - "uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", - "dev": true, - "optional": true - }, - "universalify": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.0.tgz", - "integrity": "sha1-nrHEZR3rzGcMyU8adXYjMruWd3g=" - }, - "unzip-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-1.0.2.tgz", - "integrity": "sha1-uYTwh3/AqJwsdzzB73tbIytbBv4=" - }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "dev": true, - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true + }, + "is-glob": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", + "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "dev": true, + "requires": { + "is-extglob": "2.1.1" + } + }, + "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" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "lodash": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", + "dev": true + }, + "micromatch": { + "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.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.9", + "object.pick": "1.3.0", + "regex-not": "1.0.2", + "snapdragon": "0.8.2", + "to-regex": "3.0.2" + } + }, + "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" + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "1.0.2" + } + }, + "watchpack": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.5.0.tgz", + "integrity": "sha512-RSlipNQB1u48cq0wH/BNfCu1tD/cJ8ydFIkNYhp9o+3d+8unClkIovpW5qpFPgmL9OE48wfAnlZydXByWP82AA==", + "dev": true, + "requires": { + "chokidar": "2.0.3", + "graceful-fs": "4.1.11", + "neo-async": "2.5.0" + } } } }, - "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=", - "requires": { - "prepend-http": "1.0.4" - } - }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "requires": { - "inherits": "2.0.1" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" - } - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "validate-npm-package-license": { - "version": "3.0.1", - "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", - "spdx-expression-parse": "1.0.4" - } - }, - "vm-browserify": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", - "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", - "dev": true, - "requires": { - "indexof": "0.0.1" - } - }, - "watchpack": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.3.1.tgz", - "integrity": "sha1-fYaTkHsozmAT5/NhCqKhrPB9rYc=", - "dev": true, - "requires": { - "async": "2.5.0", - "chokidar": "1.7.0", - "graceful-fs": "4.1.11" - } + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true }, "webpack": { "version": "2.7.0", @@ -4286,15 +11142,28 @@ "source-map": "0.5.6" } }, + "whatwg-url": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.3.0.tgz", + "integrity": "sha512-rM+hE5iYKGPAOu05mIdJR47pYSR2vDzfrTEFRc/S8D3L60yW8BuXmUJ7Kog7x/DrokFN7JNaHKadpzjouKRRAw==", + "dev": true, + "requires": { + "lodash.sortby": "4.7.0", + "tr46": "1.0.1", + "webidl-conversions": "4.0.2" + } + }, "when": { "version": "3.7.7", "resolved": "https://registry.npmjs.org/when/-/when-3.7.7.tgz", - "integrity": "sha1-q6A/w7tzbWyIsJHQE9io5ZDYRxg=" + "integrity": "sha1-q6A/w7tzbWyIsJHQE9io5ZDYRxg=", + "dev": true }, "which": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/which/-/which-1.2.4.tgz", "integrity": "sha1-FVf5YIBgTlsRs1meufRbUKnv1yI=", + "dev": true, "requires": { "is-absolute": "0.1.7", "isexe": "1.1.2" @@ -4306,6 +11175,46 @@ "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", "dev": true }, + "widest-line": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-1.0.0.tgz", + "integrity": "sha1-DAnIXCqUaD0Nfq+O4JfVZL8OEFw=", + "dev": true, + "requires": { + "string-width": "1.0.2" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "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" + } + }, + "string-width": { + "version": "1.0.2", + "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", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + } + } + }, + "win-release": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/win-release/-/win-release-1.1.1.tgz", + "integrity": "sha1-X6VeAr58qTTt/BJmVjLoSbcuUgk=", + "dev": true, + "requires": { + "semver": "5.3.0" + } + }, "window-size": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", @@ -4315,7 +11224,8 @@ "winreg": { "version": "0.0.12", "resolved": "https://registry.npmjs.org/winreg/-/winreg-0.0.12.tgz", - "integrity": "sha1-BxBVVLoanQiXklHRKUdb/64wBrc=" + "integrity": "sha1-BxBVVLoanQiXklHRKUdb/64wBrc=", + "dev": true }, "wordwrap": { "version": "1.0.0", @@ -4358,7 +11268,8 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true }, "write": { "version": "0.2.1", @@ -4369,10 +11280,31 @@ "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" + } + }, + "xdg-basedir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-2.0.0.tgz", + "integrity": "sha1-7byQPMOF/ARSPZZqM1UEtVBNG9I=", + "dev": true, + "requires": { + "os-homedir": "1.0.2" + } + }, "xml2js": { "version": "0.4.17", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.17.tgz", "integrity": "sha1-F76T6q4/O3eTWceVtBlwWogX6Gg=", + "dev": true, "requires": { "sax": "1.2.4", "xmlbuilder": "4.2.1" @@ -4382,10 +11314,23 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-4.2.1.tgz", "integrity": "sha1-qlijBBoGb5DqoWwvU4n/GfP0YaU=", + "dev": true, "requires": { "lodash": "4.17.4" } }, + "xmldom": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz", + "integrity": "sha1-1QH5ezvbQDr4757MIFcxh6rawOk=", + "dev": true + }, + "xregexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.0.0.tgz", + "integrity": "sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg==", + "dev": true + }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", @@ -4398,6 +11343,12 @@ "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", "dev": true }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, "yargs": { "version": "6.6.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", @@ -4474,6 +11425,55 @@ "dev": true } } + }, + "yauzl": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.9.1.tgz", + "integrity": "sha1-qBmB6nCleUYTOIPwKcWCGok1mn8=", + "dev": true, + "requires": { + "buffer-crc32": "0.2.13", + "fd-slicer": "1.0.1" + } + }, + "zip": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/zip/-/zip-1.2.0.tgz", + "integrity": "sha1-rQrUImUwm+QutW/IYZThfCTmapw=", + "dev": true, + "requires": { + "bops": "0.1.1" + } + }, + "zip-dir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/zip-dir/-/zip-dir-1.0.2.tgz", + "integrity": "sha1-JT+QeurWKiGs2HIdi4gDKyQRwFE=", + "dev": true, + "requires": { + "async": "1.5.2", + "jszip": "2.6.1" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + } + } + }, + "zip-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-1.2.0.tgz", + "integrity": "sha1-qLxF9MG0lpnGuQGYuqyqzbzUugQ=", + "dev": true, + "requires": { + "archiver-utils": "1.3.0", + "compress-commons": "1.2.2", + "lodash": "4.17.4", + "readable-stream": "2.3.3" + } } } } diff --git a/package.json b/package.json index d41067a..f77aa61 100644 --- a/package.json +++ b/package.json @@ -1,29 +1,30 @@ { "name": "shield-studies-addon-utils", - "description": "Utilities for building Shield-Study Mozilla Firefox addons.", - "version": "4.1.0", - "author": "Gregg Lind ", + "description": "Utilities for building Shield-Study Mozilla Firefox add-ons.", + "version": "5.0.0-alpha1", + "author": "Mozilla", "bugs": { "url": "https://github.com/mozilla/shield-studies-addon-utils/issues" }, "dependencies": { - "assert": "^1.4.1", - "fs-extra": "^4.0.0", - "fx-runner": "^1.0.7", - "geckodriver": "^1.8.0", - "mocha": "^3.4.2", - "path": "^0.12.7", - "selenium-webdriver": "^3.4.0" + "shield-study-schemas": "^0.8.3" }, "devDependencies": { "ajv": "^4.11.2", + "assert": "^1.4.1", "doctoc": "^1.3.1", "eslint": "^4.0.0", "eslint-plugin-json": "^1.2.0", "eslint-plugin-mozilla": "^0.4.0", "fixpack": "^2.3.1", + "fs-extra": "^4.0.0", + "fx-runner": "^1.0.7", + "geckodriver": "^1.8.0", + "mocha": "^3.4.2", + "npm-run-all": "^4.1.2", "prettier": "^1.11.0", - "shield-study-schemas": "^0.8.3", + "selenium-webdriver": "^3.4.0", + "web-ext": "^2.5.0", "webpack": "^2.6.1" }, "files": [ @@ -39,19 +40,28 @@ "shield-study" ], "license": "MPL-2.0", - "main": "lib/index.js", + "main": "src/index.js", "repository": { "type": "git", - "url": "git+https://github.com/mozilla/shield-studies-addon-utils.git" + "url": "git://github.com/mozilla/shield-studies-addon-utils.git" }, "scripts": { - "build-test-addon-xpi": "./bin/make_xpi.sh", - "dist": "webpack", + "build": "cd webExtensionApis/study && webpack", + "docformat": "doctoc --title '**Contents**' docs/*.md && prettier '**/*.md' --write", "eslint": "eslint src --ext jsm --ext js --ext json", - "predist": "npm run eslint", - "prepack": "fixpack && npm run dist", - "pretest": "npm run dist && npm run build-test-addon-xpi", - "test": "export FIREFOX_BINARY=firefox && XPI_NAME=test-addon/test-addon.xpi mocha test", - "docformat": "doctoc --title '**Contents**' docs/*.md && prettier '**/*.md' --write" + "eslint-fix": "npm run eslint -- --fix", + "format": "prettier '**/*.{css,js,jsm,json,md}' --trailing-comma=all --ignore-path=.eslintignore --write", + "lint": "npm-run-all lint:*", + "lint:eslint": "npm run eslint", + "lint:fixpack": "fixpack", + "postformat": "npm run eslint-fix && fixpack", + "prebuild": "npm run lint", + "prepack": "fixpack && npm run build", + "pretest": "npm run build && npm run test-addon:bundle-utils && npm run test-addon:build", + "pretest-addon:run": "npm run pretest", + "test": "FIREFOX_BINARY=${FIREFOX_BINARY:-firefox} ADDON_ZIP=examples/test-addon/dist/shield_utils_test_add-on-1.0.0.zip mocha examples/test-addon/test/functional/ --bail", + "test-addon:build": "cd examples/test-addon && web-ext build", + "test-addon:bundle-utils": "examples/test-addon/bin/bundle-shield-studies-addon-utils.sh", + "test-addon:run": "cd examples/test-addon && web-ext run --no-reload" } } diff --git a/shield-study-helper-addon/addon/webextension/.eslintrc.json b/shield-study-helper-addon/addon/webextension/.eslintrc.json deleted file mode 100644 index 1d71c50..0000000 --- a/shield-study-helper-addon/addon/webextension/.eslintrc.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "env": { - "browser": true, - "es6": true, - "webextensions": true - }, - "extends": [ - "eslint:recommended" - ], - "rules": { - "no-console": "warn" - } -} diff --git a/src/StudyUtils.in.jsm b/src/StudyUtils.in.jsm deleted file mode 100644 index f4a5e88..0000000 --- a/src/StudyUtils.in.jsm +++ /dev/null @@ -1,831 +0,0 @@ -"use strict"; - -/* -* For an overview of what this module does, see ABOUT.md at -* github.com/mozilla/shield-studies-addon-template -* -* Note: There are a number of methods that won't work if the -* setup method has not executed (they perform a check with the -* `throwIfNotSetup` method). The setup method ensures that the -* config data passed in is valid per the studySetup schema. -*/ - - -/* -* TODO glind survey / urls & query args -* TODO glind publish as v4 -*/ -const EXPORTED_SYMBOLS = ["studyUtils"]; - -const UTILS_VERSION = require("../package.json").version; -const PACKET_VERSION = 3; - -const {utils: Cu} = Components; -Cu.import("resource://gre/modules/AddonManager.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.importGlobalProperties(["URL", "crypto", "URLSearchParams"]); - -let log; - -// telemetry utils -const CID = Cu.import("resource://gre/modules/ClientID.jsm", null); -const { TelemetryController } - = Cu.import("resource://gre/modules/TelemetryController.jsm", null); -const { TelemetryEnvironment } - = Cu.import("resource://gre/modules/TelemetryEnvironment.jsm", null); - -/* -* Set-up JSON schema validation -* Schemas are used to validate an input (here, via AJV at runtime) -* Schemas here are used for: -* - Telemetry (Ensure correct Parquet format for different types of -* outbound packets): -* - "shield-study": shield study state and outcome data common to all -* shield studies. -* - "shield-study-addon": addon-specific probe data, with `attributes` -* (used to capture feature-specific state) sent as Map(string,string). -* - "shield-study-error": data used to notify, group and count some kinds -* of errors from shield studies -* - ShieldUtils API ducktypes: -* - "weightedVariations": the array of branch name:weight pairs used to -* randomly assign the user -* to a branch -* - "webExtensionMsg": the message object passed into the -* StudyUtils.respondToWebExtensionMessage method -* - "studySetup": the options object passed into the StudyUtils.setup method -*/ -const schemas = require("./schemas.js"); -const Ajv = require("ajv/dist/ajv.min.js"); -const ajv = new Ajv(); - -var jsonschema = { - /** - * Validates input data based on a specified schema - * @param {Object} data - The data to be validated - * @param {Object} schema - The schema to validate against - * @returns {boolean} - Will return true if the data is valid - */ - validate(data, schema) { - var valid = ajv.validate(schema, data); - return {valid, errors: ajv.errors || []}; - }, - /** - * Validates input data based on a specified schema - * @param {Object} data - The data to be validated - * @param {Object} schema - The schema to validate against - * @throws Will throw an error if the data is not valid - * @returns {boolean} - Will return true if the data is valid - */ - validateOrThrow(data, schema) { - const valid = ajv.validate(schema, data); - if (!valid) { throw new Error(JSON.stringify((ajv.errors))); } - return true; - }, -}; - -/** - * Note: This is the deep merge from the addon-sdk (sdk/util/object.js). - * Probably deeper than we need. Unlike the shallow merge with the - * spread operator (const c = {...a, ...b}), this function can be configured - * to copy non-enumerable properties, symbols, and property descriptors. - * - * Merges all the properties of all arguments into first argument. If two or - * more argument objects have own properties with the same name, the property - * is overridden, with precedence from right to left, implying, that properties - * of the object on the left are overridden by a same named property of the - * object on the right. - * - * Any argument given with "falsy" value - commonly `null` and `undefined` in - * case of objects - are skipped. - * - * @examples - * var a = { bar: 0, a: 'a' } - * var b = merge(a, { foo: 'foo', bar: 1 }, { foo: 'bar', name: 'b' }); - * b === a // true - * b.a // 'a' - * b.foo // 'bar' - * b.bar // 1 - * b.name // 'b' - * - * @param {...Object} source - two or more object arguments - * @returns {Object} - the resulting merged object - */ -function merge(source) { - const optionsDefault = { - names: true, - symbols: true, - nonEnumerables: true, - }; - /** - * Gets object's own property symbols and/or names, including non-enumerables - * by default - * @param {Object} object - the object for which to get own property symbols - * and names - * @param {Object} options - object indicating what kinds of properties to - * merge - * @param {boolean} options.name - True if function should return object's own - * property names - * @param {boolean} options.symbols - True if function should return object's - * own property symbols - * @param {boolean} options.nonEnumerables - True if function should return - * object's non-enumerable own property names - * @returns {string[]|symbol[]} - An array of own property names and/or symbols - * for object - */ - function getOwnPropertyIdentifiers(object, options = optionsDefault) { - const symbols = !options.symbols ? [] : - Object.getOwnPropertySymbols(object); - - // eslint-disable-next-line - const names = !options.names ? [] : - options.nonEnumerables ? Object.getOwnPropertyNames(object) : - Object.keys(object); - return [...names, ...symbols]; - } - /* - * descriptor: an object whose own enumerable properties constitute descriptors - * for the properties from arguments[1]+ to be defined or modified in - * arguments[0] - */ - const descriptor = {}; - /* - * `Boolean` converts the first parameter to a boolean value. Any object is - * converted to `true` where `null` and `undefined` becames `false`. Therefore - * the `filter` method will keep only objects that are defined and not null. - */ - Array.slice(arguments, 1).filter(Boolean).forEach((properties) => { - getOwnPropertyIdentifiers(properties).forEach((name) => { - descriptor[name] = Object.getOwnPropertyDescriptor(properties, name); - }); - }); - return Object.defineProperties(source, descriptor); -} - -/** -* Appends a query string to a url. -* @param {string} url - a base url to append; must be static (data) or external -* @param {Object} args - query arguments, one or more object literal used to -* build a query string -* @returns {string} - an absolute url appended with a query string -*/ -function mergeQueryArgs(url, ...args) { - // currently left to right - // TODO, glind, decide order of merge here - // TODO, use Object.assign, or ES7 spread - const U = new URL(url); - // get the query string already attached to url, if it exists - let q = U.search || "?"; - // create an interface to interact with the query string - q = new URLSearchParams(q); - const merged = merge({}, ...args); - // Set each search parameter in "merged" to its value in the query string, - // building up the query string one search parameter at a time. - Object.keys(merged).forEach((k) => { - // k, the search parameter (ex: fxVersion) - // q.get(k), returns the value of k, in query string, q (ex: 57.0.1a) - log.debug(q.get(k), k, merged[k]); - q.set(k, merged[k]); - }); - // append our new query string to the URL object made with "url" - U.search = q.toString(); - // return the full url, with the appended query string - return U.toString(); -} - -// sampling utils -/** -* @async -* Converts a string into its sha256 hexadecimal representation. -* Note: This is ultimately used to make a hash of the user's telemetry clientID -* and the study name. -* @param {string} message - The message to convert. -* @returns {string} - a hexadecimal, 256-bit hash -*/ -async function sha256(message) { - // encode as UTF-8 - const msgBuffer = new TextEncoder("utf-8").encode(message); - // hash the message - const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer); - // convert ArrayBuffer to Array - const hashArray = Array.from(new Uint8Array(hashBuffer)); - // convert bytes to hex string - const hashHex - = hashArray.map(b => ("00" + b.toString(16)).slice(-2)).join(""); - return hashHex; -} - -/** -* Converts an array of length N into a cumulative sum array of length N, -* where n_i = sum(array.slice(0,i)) i.e. each element is the sum of all -* elements up to and including that element -* This is ultimately used for turning sample weights (AKA weightedVariations) -* into right hand limits (>= X) to deterministically select which variation -* a user receives. -* @example [.25,.3,.45] => [.25,.55,1.0]; if a user's sample weight were .25, -* they would fall into the left-most bucket -* @param {Number[]} arr - An array of sample weights (0 <= sample weight < 1) -* @returns {Number[]} - A cumulative sum array of sample weights -* (0 <= sample weight <= 1) -*/ -function cumsum(arr) { - return arr.reduce(function(r, c, i) { - r.push((r[i - 1] || 0) + c); - return r; - }, [] ); -} - -/** -* Given sample weights (weightedVariations) and a particular position -* (fraction), return a variation. If no fraction given, return a variation -* at random fraction proportional to the weightVariations object -* @param {Object[]} weightedVariations - the array of branch name:weight pairs -* used to randomly assign the user to a branch -* @param {Number} fraction - a number (0 <= fraction < 1) -* @returns {Object} - the variation object in weightedVariations for the given -* fraction -*/ -function chooseWeighted(weightedVariations, fraction = Math.random()) { - /* - weightedVaiations, list of: - { - name: string of any length - weight: float >= 0 - } - */ - jsonschema.validateOrThrow(weightedVariations, schemas.weightedVariations); - - var weights = weightedVariations.map(x => x.weight || 1); - const partial = cumsum(weights); - const total = weights.reduce((a, b) => a + b); - for (let ii = 0; ii < weightedVariations.length; ii++) { - if (fraction <= partial[ii] / total) { - return weightedVariations[ii]; - } - } - return null; -} - -/** -* @async -* Converts a string into a fraction (0 <= fraction < 1) based on the first -* X bits of its sha256 hexadecimal representation -* Note: Salting (adding the study name to the telemetry clientID) ensures -* that the same user gets a different bucket/hash for each study. -* Hashing of the salted string ensures uniform hashing; i.e. that every -* bucket/variation gets filled. -* @param {string} saltedString - a salted string used to create a hash for -* the user -* @param {Number} bits - The first number of bits to use in the sha256 hex -* representation -* @returns {Number} - a fraction (0 <= fraction < 1) -*/ -async function hashFraction(saltedString, bits = 12) { - const hash = await sha256(saltedString); - return parseInt(hash.substr(0, bits), 16) / Math.pow(16, bits); -} - -/** -* Class representing utilities for shield studies. -*/ -class StudyUtils { - /** - * Create a StudyUtils instance. - */ - constructor() { - /* - * TODO glind Answer: no. see if you can merge the construtor and setup - * and export the class, rather than a singleton - */ - /** - * Handles a message received by the webExtension, sending a response back. - * @param {Object} webExtensionMsg object, see its schema - * @param {boolean} webExtensionMsg.shield - Whether or not the message - * is a shield message (intended for StudyUtils) - * @param {string} webExtensionMsg.msg - StudyUtils method to be called - *from the webExtension - * @param {*} webExtensionMsg.data - Data sent from webExtension - * @param {Object} sender - Details about the message sender, see - * runtime.onMessage MDN docs - * @param {responseCallback} sendResponse - The callback to send a response - * back to the webExtension - * @returns {boolean|undefined} - true if the message has been processed - * (shield message) or ignored (non-shield message) - */ - this.respondToWebExtensionMessage - = function({shield, msg, data}, sender, sendResponse) { - // @TODO glind: make sure we're using the webExtensionMsg schema - if (!shield) return true; - const allowedMethods = ["endStudy", "telemetry", "info"]; - if (!allowedMethods.includes(msg)) { - const errStr1 = "respondToWebExtensionMessage:"; - const errStr2 = "is not in allowed studyUtils methods:"; - throw new Error(`${errStr1} "${msg}" ${errStr2} ${allowedMethods}`); - } - /* - * handle async - * Execute the StudyUtils method requested by the webExtension - * then send the webExtension a response with their return value - */ - Promise.resolve(this[msg](data)).then( - function(ans) { - log.debug("respondingTo", msg, ans); - sendResponse(ans); - }, - // function error eventually - ); - return true; - /* Ensure this method is bound to the instance of studyUtils, see - * callsite in bootstrap.js - * TODO glind: bdanforth's claim: making this function a StudyUtils - * method would also do this. - */ - }.bind(this); - - /* - * Expose sampling methods onto the exported studyUtils singleton, for use - * by any Components.utils-importing module - */ - this.sample = { - - sha256, - cumsum, - chooseWeighted, - hashFraction, - }; - // expose schemas - this.schemas = schemas; - - // expose validation methods - this.jsonschema = jsonschema; - - this.REASONS = REASONS; - } - - /** - * Checks if the StudyUtils.setup method has been called - * @param {string} name - the name of a StudyUtils method - * @returns {void} - */ - throwIfNotSetup(name = "unknown") { - if (!this._isSetup) throw new Error( - name + ": this method can't be used until `setup` is called" - ); - } - - /** - * Validates the studySetup object passed in from the addon. - * @param {Object} config - the studySetup object, see schema.studySetup.json - * @returns {StudyUtils} - the StudyUtils class instance - */ - setup(config) { - log = createLog("shield-study-utils", config.log.studyUtils.level); - - log.debug("setting up!"); - jsonschema.validateOrThrow(config, schemas.studySetup); - - this.config = config; - this._isSetup = true; - return this; - } - - /** - * Resets the state of the study. Suggested use is for testing. - * @returns {void} - */ - reset() { - this.config = {}; - delete this._variation; - this._isSetup = false; - } - - /** - * @async - * Opens a new tab that loads a page with the specified URL. - * @param {string} url - the url of a page - * @param {Object} params - optional, see - * https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Method/addTab - * @returns {void} - */ - async openTab(url, params = {}) { - this.throwIfNotSetup("openTab"); - log.debug(url, params); - log.debug("opening this formatted tab", url, params); - if (!Services.wm.getMostRecentWindow("navigator:browser").gBrowser) { - /* - * Automated tests run faster than Firefox opens windows. - * TODO: Find less gross way to do this - * Wait for the window to be opened - */ - await new Promise(resolve => setTimeout(resolve, 30000)); - } - Services.wm.getMostRecentWindow("navigator:browser") - .gBrowser.addTab(url, params); - } - - /** - * @async - * Gets the telemetry client ID for the user. - * @returns {string} - the telemetry client ID - */ - async getTelemetryId() { - const id = TelemetryController.clientID; - /* istanbul ignore next */ - if (id === undefined) { - return await CID.ClientIDImpl._doLoadClientID(); - } - return id; - } - - /** - * Sets the variation for the StudyUtils instance. - * @param {Object} variation - the study variation for this user - * @returns {StudyUtils} - the StudyUtils class instance - */ - setVariation(variation) { - this.throwIfNotSetup("setVariation"); - this._variation = variation; - return this; - } - - /** - * Gets the variation for the StudyUtils instance. - * @returns {Object} - the study variation for this user - */ - getVariation() { - this.throwIfNotSetup("getvariation"); - return this._variation; - } - - /** - * @async - * Deterministically selects and returns the study variation for the user. - * @param {Object[]} weightedVariations - see schema.weightedVariations.json - * @param {Number} rng - randomly generated number (0 <= rng < 1) of the form - * returned by Math.random; can be set explicitly for testing - * @returns {Object} - the study variation for this user - */ - async deterministicVariation(weightedVariations, rng = null) { - // hash the studyName and telemetryId to get the same branch every time. - this.throwIfNotSetup("deterministicVariation needs studyName"); - // this is the standard arm choosing method - let fraction = rng; - if (fraction === null) { - const clientId = await this.getTelemetryId(); - const studyName = this.config.study.studyName; - fraction = await this.sample.hashFraction(studyName + clientId, 12); - } - return this.sample.chooseWeighted(weightedVariations, fraction); - } - - /** - * Gets the Shield recipe client ID. - * @returns {string} - the Shield recipe client ID. - */ - getShieldId() { - const key = "extensions.shield-recipe-client.user_id"; - return Services.prefs.getCharPref(key, ""); - } - - /** - * Packages information about the study into an object. - * @returns {Object} - study information, see schema.studySetup.json - */ - info() { - log.debug("getting info"); - this.throwIfNotSetup("info"); - return { - studyName: this.config.study.studyName, - addon: this.config.addon, - variation: this.getVariation(), - shieldId: this.getShieldId(), - }; - } - - /** - * Get the telemetry configuration for the study. - * @returns {Object} - the telemetry cofiguration, see schema.studySetup.json - */ - // TODO glind, maybe this is getter / setter? - get telemetryConfig() { - this.throwIfNotSetup("telemetryConfig"); - return this.config.study.telemetry; - } - - /** - * Sends an 'enter' telemetry ping for the study; should be called on addon - * startup for the reason ADDON_INSTALL. For more on study states like 'enter' - * see ABOUT.md at github.com/mozilla/shield-studies-addon-template - * @returns {void} - */ - firstSeen() { - log.debug(`firstSeen`); - this.throwIfNotSetup("firstSeen uses telemetry."); - this._telemetry({study_state: "enter"}, "shield-study"); - } - - /** - * Marks the study's telemetry pings as being part of this experimental - * cohort in a way that downstream data pipeline tools (like ExperimentsViewer) - * can use it. - * @returns {void} - */ - setActive() { - this.throwIfNotSetup("setActive uses telemetry."); - const info = this.info(); - log.debug( - "marking TelemetryEnvironment", - info.studyName, - info.variation.name - ); - TelemetryEnvironment.setExperimentActive( - info.studyName, - info.variation.name - ); - } - - /** - * Removes the study from the active list of telemetry experiments - * @returns {void} - */ - unsetActive() { - this.throwIfNotSetup("unsetActive uses telemetry."); - const info = this.info(); - log.debug( - "unmarking TelemetryEnvironment", - info.studyName, - info.variation.name - ); - TelemetryEnvironment.setExperimentInactive(info.studyName); - } - - /** - * Uninstalls the shield study addon, given its addon id. - * @param {string} id - the addon id - * @returns {void} - */ - uninstall(id) { - if (!id) id = this.info().addon.id; - if (!id) { - this.throwIfNotSetup("uninstall needs addon.id as arg or from setup."); - } - log.debug(`about to uninstall ${id}`); - AddonManager.getAddonByID(id, addon => addon.uninstall()); - } - - /** - * @async - * Adds the study to the active list of telemetry experiments and sends the - * "installed" telemetry ping if applicable - * @param {string} reason - The reason the addon has started up - * @returns {void} - */ - async startup({reason}) { - this.throwIfNotSetup("startup"); - log.debug(`startup ${reason}`); - this.setActive(); - if (reason === REASONS.ADDON_INSTALL) { - this._telemetry({study_state: "installed"}, "shield-study"); - } - } - - /** - * @async - * Ends the study: - * - Removes the study from the active list of telemetry experiments - * - Opens a new tab at a specified URL, if present (e.g. for a survey) - * - Sends a telemetry ping about the nature of the ending - * (positive, neutral, negative) - * - Sends an exit telemetry ping - * @param {Object} param - A details object describing why the study is ending - * @param {string} param.reason - The reason the study is ending, see - * schema.studySetup.json - * @param {string} param.fullname - optional, the full name of the study - * state, see schema.studySetup.json - * @returns {void} - */ - async endStudy({reason, fullname}) { - this.throwIfNotSetup("endStudy"); - if (this._isEnding) { - log.debug("endStudy, already ending!"); - return; - } - this._isEnding = true; - log.debug(`endStudy ${reason}`); - this.unsetActive(); - // TODO glind, think about reason vs fullname - // TODO glind, think about race conditions for endings, ensure only one exit - /* - * Check if the study ending shows the user a page in a new tab - * (ex: survey, explanation, etc.) - */ - const ending = this.config.study.endings[reason]; - if (ending) { - // baseUrl: needs to be appended with query arguments before use, - // exactUrl: used as is - const {baseUrl, exactUrl} = ending; - if (exactUrl) { - this.openTab(exactUrl); - } else if (baseUrl) { - const qa = await this.endingQueryArgs(); - qa.reason = reason; - qa.fullreason = fullname; - const fullUrl = mergeQueryArgs(baseUrl, qa); - log.debug(baseUrl, fullUrl); - this.openTab(fullUrl); - } - } - switch (reason) { - case "ineligible": - case "expired": - case "user-disable": - case "ended-positive": - case "ended-neutral": - case "ended-negative": - this._telemetry({study_state: reason, fullname}, "shield-study"); - break; - default: - this._telemetry( - { - study_state: "ended-neutral", - study_state_fullname: reason, - }, - "shield-study" - ); - // unless we know better TODO grl - } - // these are all exits - this._telemetry({study_state: "exit"}, "shield-study"); - this.uninstall(); // TODO glind. should be controllable by arg? - } - - /** - * @async - * Builds an object whose properties are query arguments that can be - * appended to a study ending url - * @returns {Object} - the query arguments for the study - */ - async endingQueryArgs() { - // TODO glind, make this back breaking! - this.throwIfNotSetup("endingQueryArgs"); - const info = this.info(); - const who = await this.getTelemetryId(); - const queryArgs = { - shield: PACKET_VERSION, - study: info.studyName, - variation: info.variation.name, - updateChannel: Services.appinfo.defaultUpdateChannel, - fxVersion: Services.appinfo.version, - addon: info.addon.version, // addon version - who, // telemetry clientId - }; - queryArgs.testing = Number(!this.telemetryConfig.removeTestingFlag); - return queryArgs; - } - - /** - * @async - * Validates and submits telemetry pings from StudyUtils. - * @param {Object} data - the data to send as part of the telemetry packet - * @param {string} bucket - the type of telemetry packet to be sent - * @returns {Promise|boolean} - A promise that resolves with the ping id - * once the ping is stored or sent, or false if - * - there is a validation error, - * - the packet is of type "shield-study-error" - * - the study's telemetryConfig.send is set to false - */ - async _telemetry(data, bucket = "shield-study-addon") { - log.debug(`telemetry in: ${bucket} ${JSON.stringify(data)}`); - this.throwIfNotSetup("_telemetry"); - const info = this.info(); - const payload = { - version: PACKET_VERSION, - study_name: info.studyName, - branch: info.variation.name, - addon_version: info.addon.version, - shield_version: UTILS_VERSION, - type: bucket, - data, - testing: !this.telemetryConfig.removeTestingFlag, - }; - - let validation; - /* istanbul ignore next */ - try { - validation = jsonschema.validate(payload, schemas[bucket]); - } catch (err) { - // Catch failures of unknown origin (could be library, addon, system...) - // if validation broke, GIVE UP. - log.error(err); - return false; - } - /* - * Handle validation errors by sending a "shield-study-error" - * telemetry ping with the error report. - * If the invalid payload is itself of type "shield-study-error", - * throw an error (to avoid a possible infinite loop). - */ - if (validation.errors.length) { - const errorReport = { - "error_id": "jsonschema-validation", - "error_source": "addon", - "severity": "fatal", - "message": JSON.stringify(validation.errors), - }; - if (bucket === "shield-study-error") { - // log: if it's a warn or error, it breaks jpm test - log.warn("cannot validate shield-study-error", data, bucket); - return false; // just die, maybe should have a super escape hatch? - } - return this.telemetryError(errorReport); - } - // emit(TelemetryWatcher, 'telemetry', [bucket, payload]); - log.debug(`telemetry: ${JSON.stringify(payload)}`); - // FIXME marcrowo: addClientId makes the ping not appear in test? - // seems like a problem with Telemetry, not the shield-study-utils library - const telOptions = {addClientId: true, addEnvironment: true}; - if (!this.telemetryConfig.send) { - log.debug("NOT sending. `telemetryConfig.send` is false"); - return false; - } - return TelemetryController.submitExternalPing(bucket, payload, telOptions); - } - - /** - * @async - * Validates and submits telemetry pings from the addon; mostly from - * webExtension messages. - * @param {Object} data - the data to send as part of the telemetry packet - * @returns {Promise|boolean} - see StudyUtils._telemetry - */ - async telemetry(data) { - log.debug(`telemetry ${JSON.stringify(data)}`); - const toSubmit = { - attributes: data, - }; - // lets check early, and respond with something useful? - return this._telemetry(toSubmit, "shield-study-addon"); - } - - /** - * Submits error report telemetry pings. - * @param {Object} errorReport - the error report, see StudyUtils._telemetry - * @returns {Promise|boolean} - see StudyUtils._telemetry - */ - telemetryError(errorReport) { - return this._telemetry(errorReport, "shield-study-error"); - } - - /** - * Sets the logging level. This is can be called from the addon, even after the - * log has been created. - * @param {string} descriptor - the Log level (e.g. "trace", "error", ...) - * @returns {void} - */ - setLoggingLevel(descriptor) { - log.level = Log.Level[descriptor]; - } - -} - -/** -* Creates a log for debugging. -* Note: Log.jsm is used over Console.log/warn/error because: -* - Console has limited log levels -* - Console is not pref-controllable. Log can be turned on and off using -* config.log (see ./addon/Config.jsm in -* github.com/mozilla/shield-study-addon-template) -* - Console can create linting errors and warnings. -* @param {string} name - the name of the Logger instance -* @param {string} levelWord - the Log level (e.g. "trace", "error", ...) -* @returns {Object} - the Logger instance, see gre/modules/Log.jsm -*/ -function createLog(name, levelWord) { - Cu.import("resource://gre/modules/Log.jsm"); - var L = Log.repository.getLogger(name); - L.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter())); - // should be a config / pref - L.level = Log.Level[levelWord] || Log.Level.Debug; - L.debug("log made", name, levelWord, Log.Level[levelWord]); - return L; -} - -// addon state change reasons -const REASONS = { - APP_STARTUP: 1, // The application is starting up. - APP_SHUTDOWN: 2, // The application is shutting down. - ADDON_ENABLE: 3, // The add-on is being enabled. - ADDON_DISABLE: 4, // The add-on is being disabled. (Also sent at uninstall) - ADDON_INSTALL: 5, // The add-on is being installed. - ADDON_UNINSTALL: 6, // The add-on is being uninstalled. - ADDON_UPGRADE: 7, // The add-on is being upgraded. - ADDON_DOWNGRADE: 8, // The add-on is being downgraded. -}; -for (const r in REASONS) { REASONS[REASONS[r]] = r; } - -// Actually create the singleton. -var studyUtils = new StudyUtils(); - -// to make this work with webpack! -this.EXPORTED_SYMBOLS = EXPORTED_SYMBOLS; -this.studyUtils = studyUtils; diff --git a/src/schema.webExtensionMsg.json b/src/schema.webExtensionMsg.json deleted file mode 100644 index 5c5814f..0000000 --- a/src/schema.webExtensionMsg.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "title": "webExtension browserMessage", - "type": "object", - "properties": { - "shield": { - "type": "boolean" - }, - "msg": { - "type": "string", - "enum": [ - "endStudy", - "telemetry", - "info" - ] - }, - "data": { - "type": "object" - } - }, - "required": [ - "shield", - "msg" - ] -} diff --git a/src/schemas.js b/src/schemas.js deleted file mode 100644 index 27ecb3d..0000000 --- a/src/schemas.js +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - "shield-study": require("shield-study-schemas/schemas-client/shield-study.schema.json"), - "shield-study-addon": require("shield-study-schemas/schemas-client/shield-study-addon.schema.json"), - "shield-study-error": require("shield-study-schemas/schemas-client/shield-study-error.schema.json"), - "studySetup": require("./schema.studySetup.json"), - "webExtensionMsg": require("./schema.webExtensionMsg.json"), - "weightedVariations": require("./schema.weightedVariations.json"), -}; diff --git a/test-addon/.gitignore b/test-addon/.gitignore deleted file mode 100644 index 5561a3d..0000000 --- a/test-addon/.gitignore +++ /dev/null @@ -1 +0,0 @@ -StudyUtils.jsm diff --git a/test-addon/README.md b/test-addon/README.md deleted file mode 100644 index 40af997..0000000 --- a/test-addon/README.md +++ /dev/null @@ -1,3 +0,0 @@ -This is an example add-on that is used to test the shield-study-utils library. - -We include the library by obtaining a copy of dist/StudyUtils.jsm (created by `npm run dist` = `webpack`). diff --git a/test-addon/bootstrap.js b/test-addon/bootstrap.js deleted file mode 100644 index 4bccfe5..0000000 --- a/test-addon/bootstrap.js +++ /dev/null @@ -1,11 +0,0 @@ -const { classes: Cc, interfaces: Ci, utils: Cu } = Components; -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "studyUtils", "resource://test-addon/StudyUtils.jsm"); - -this.install = function(data, reason) {}; - -this.startup = async function(data, reason) {}; - -this.shutdown = function(data, reason) {}; - -this.uninstall = function(data, reason) {}; diff --git a/test-addon/build-includes.txt b/test-addon/build-includes.txt deleted file mode 100644 index 667c77d..0000000 --- a/test-addon/build-includes.txt +++ /dev/null @@ -1,5 +0,0 @@ -bootstrap.js -chrome.manifest -install.rdf -StudyUtils.jsm -utils.jsm diff --git a/test-addon/chrome.manifest b/test-addon/chrome.manifest deleted file mode 100644 index 9721aaa..0000000 --- a/test-addon/chrome.manifest +++ /dev/null @@ -1 +0,0 @@ -resource test-addon . diff --git a/test-addon/install.rdf b/test-addon/install.rdf deleted file mode 100644 index 41781f8..0000000 --- a/test-addon/install.rdf +++ /dev/null @@ -1,22 +0,0 @@ - - - - - shield-study-utils-test@mozilla.org - 2 - true - false - 0.1.0 - Test Add-on for shield-study-utils - Add-on whose sole purpose of existence is to test the shield-study-utils library. - true - - - - {ec8030f7-c20a-464f-9b0e-13a3a9e97384} - 54 - * - - - - diff --git a/test-addon/utils.jsm b/test-addon/utils.jsm deleted file mode 100644 index 1472083..0000000 --- a/test-addon/utils.jsm +++ /dev/null @@ -1,41 +0,0 @@ -/* eslint no-unused-vars: "off" */ - -const { studyUtils } = Components.utils.import("resource://test-addon/StudyUtils.jsm", {}); -Components.utils.import("resource://gre/modules/TelemetryArchive.jsm"); -Components.utils.import("resource://gre/modules/Console.jsm"); - -var EXPORTED_SYMBOLS = ["fakeSetup", "getMostRecentPingsByType"]; - -function fakeSetup() { - studyUtils.setup({ - study: { - studyName: "shield-utils-test", - endings: { - "expired": { - "baseUrl": "http://www.example.com/?reason=expired", - }, - }, - telemetry: { send: true, removeTestingFlag: false }, - }, - log: { - // Fatal: 70, Error: 60, Warn: 50, Info: 40, Config: 30, Debug: 20, Trace: 10, All: -1, - studyUtils: { - level: "Warn", - }, - }, - addon: {id: "1", version: "1"}, - }); - studyUtils.setVariation({ name: "puppers", weight: "2" }); -} - -// Returns array of pings of type `type` in sorted order by timestamp -// first element is most recent ping -async function getMostRecentPingsByType(type) { - const pings = await TelemetryArchive.promiseArchivedPingList(); - - const filteredPings = pings.filter(p => p.type === type); - filteredPings.sort((a, b) => b.timestampCreated - a.timestampCreated); - - const pingData = filteredPings.map(ping => TelemetryArchive.promiseArchivedPingById(ping.id)); - return Promise.all(pingData); -} diff --git a/test/shield_utils_test.js b/test/shield_utils_test.js deleted file mode 100644 index d54b2ec..0000000 --- a/test/shield_utils_test.js +++ /dev/null @@ -1,188 +0,0 @@ -/* eslint-env node, mocha */ - -const assert = require("assert"); -const utils = require("./utils"); -const firefox = require("selenium-webdriver/firefox"); -const Context = firefox.Context; - -// TODO create new profile per test? -// then we can test with a clean profile every time - -describe("Shield Study Utils Functional Tests", function() { - // This gives Firefox time to start, and us a bit longer during some of the tests. - this.timeout(15000); - - let driver; - - before(async() => { - driver = await utils.promiseSetupDriver(); - // install the addon (note: returns addon id) - await utils.installAddon(driver); - }); - - after(() => driver.quit()); - - it("should return the correct variation", async() => { - const variation = await driver.executeAsyncScript(async(callback) => { - const { studyUtils } = Components.utils.import("resource://test-addon/StudyUtils.jsm", {}); - // TODO move this to a Config.jsm file - const studyConfig = { - studyName: "shieldStudyUtilsTest", - "weightedVariations": [ - {"name": "control", - "weight": 1}, - {"name": "kittens", - "weight": 1.5}, - {"name": "puppers", - "weight": 2}, // we want more puppers in our sample - ], - }; - - const sample = studyUtils.sample; - const hashFraction = await sample.hashFraction("test"); - const chosenVariation = await sample.chooseWeighted(studyConfig.weightedVariations, hashFraction); - callback(chosenVariation); - }); - assert(variation.name === "puppers"); - }); - - it("telemetry should be working", async() => { - const shieldTelemetryPing = await driver.executeAsyncScript(async(callback) => { - const { fakeSetup, getMostRecentPingsByType } = Components.utils.import("resource://test-addon/utils.jsm", {}); - const { studyUtils } = Components.utils.import("resource://test-addon/StudyUtils.jsm", {}); - Components.utils.import("resource://gre/modules/TelemetryArchive.jsm"); - - fakeSetup(); - - await studyUtils.telemetry({ "foo": "bar" }); - - // TODO Fix this hackiness; caused by addClientId option in submitExternalPing - // The ping seems to be sending (appears in about:telemetry) but does not appear - // in the pings array - await new Promise(resolve => setTimeout(resolve, 1000)); - - const shieldPings = await getMostRecentPingsByType("shield-study-addon"); - callback(shieldPings[0]); - }); - assert(shieldTelemetryPing.payload.data.attributes.foo === "bar"); - }); - - describe("test the library's \"startup\" process", function() { - it("should send the correct ping on first seen", async() => { - const firstSeenPing = await driver.executeAsyncScript(async(callback) => { - const { fakeSetup, getMostRecentPingsByType } = Components.utils.import("resource://test-addon/utils.jsm", {}); - const { studyUtils } = Components.utils.import("resource://test-addon/StudyUtils.jsm", {}); - Components.utils.import("resource://gre/modules/TelemetryArchive.jsm"); - - fakeSetup(); - - studyUtils.firstSeen(); - - const studyPings = await getMostRecentPingsByType("shield-study"); - callback(studyPings[0]); - }); - assert(firstSeenPing.payload.data.study_state === "enter"); - }); - - it("should set the experiment to active in Telemetry", async() => { - const activeExperiments = await driver.executeAsyncScript(async(callback) => { - const { fakeSetup } = Components.utils.import("resource://test-addon/utils.jsm", {}); - const { studyUtils } = Components.utils.import("resource://test-addon/StudyUtils.jsm", {}); - Components.utils.import("resource://gre/modules/TelemetryEnvironment.jsm"); - - fakeSetup(); - - studyUtils.setActive(); - - callback(TelemetryEnvironment.getActiveExperiments()); - }); - assert(activeExperiments.hasOwnProperty("shield-utils-test")); - }); - - it("should send the correct telemetry ping on first install", async() => { - const installedPing = await driver.executeAsyncScript(async(callback) => { - const { fakeSetup, getMostRecentPingsByType } = Components.utils.import("resource://test-addon/utils.jsm", {}); - const { studyUtils } = Components.utils.import("resource://test-addon/StudyUtils.jsm", {}); - Components.utils.import("resource://gre/modules/TelemetryArchive.jsm"); - - fakeSetup(); - - await studyUtils.startup({reason: 5}); // ADDON_INSTALL = 5 - - const studyPings = await getMostRecentPingsByType("shield-study"); - callback(studyPings[0]); - }); - assert(installedPing.payload.data.study_state === "installed"); - }); - }); - - describe("test the library's endStudy() function", function() { - before(async() => { - await driver.executeAsyncScript(async(callback) => { - const { fakeSetup } = Components.utils.import("resource://test-addon/utils.jsm", {}); - const { studyUtils } = Components.utils.import("resource://test-addon/StudyUtils.jsm", {}); - - fakeSetup(); - - // TODO add tests for other reasons (?) - await studyUtils.endStudy({reason: "expired", fullname: "TEST_FULLNAME"}); - callback(); - }); - }); - - it("should set the experiment as inactive", async() => { - const activeExperiments = await driver.executeAsyncScript(async(callback) => { - Components.utils.import("resource://gre/modules/TelemetryEnvironment.jsm"); - callback(TelemetryEnvironment.getActiveExperiments()); - }); - assert(!activeExperiments.hasOwnProperty("shield-utils-test")); - }); - - describe("test the opening of a URL at the end of the study", function() { - it("should open a new tab", async() => { - const newTabOpened = await driver.wait(async() => { - const handles = await driver.getAllWindowHandles(); - return handles.length === 2; // opened a new tab - }, 3000); - assert(newTabOpened); - }); - - it("should open a new tab to the correct URL", async() => { - const currentHandle = await driver.getWindowHandle(); - driver.setContext(Context.CONTENT); - // Find the new window handle. - let newWindowHandle = null; - const handles = await driver.getAllWindowHandles(); - for (const handle of handles) { - if (handle !== currentHandle) { - newWindowHandle = handle; - } - } - const correctURLOpened = await driver.wait(async() => { - await driver.switchTo().window(newWindowHandle); - const currentURL = await driver.getCurrentUrl(); - return currentURL.startsWith("http://www.example.com/?reason=expired"); - }); - assert(correctURLOpened); - }); - }); - - it("should send the correct reason telemetry", async() => { - const pings = await driver.executeAsyncScript(async(callback) => { - const { getMostRecentPingsByType } = Components.utils.import("resource://test-addon/utils.jsm", {}); - const studyPings = await getMostRecentPingsByType("shield-study"); - callback(studyPings[1]); // ping before the most recent ping - }); - assert(pings.payload.data.study_state === "expired"); - }); - - it("should send the uninstall telemetry", async() => { - const pings = await driver.executeAsyncScript(async(callback) => { - const { getMostRecentPingsByType } = Components.utils.import("resource://test-addon/utils.jsm", {}); - const studyPings = await getMostRecentPingsByType("shield-study"); - callback(studyPings[0]); - }); - assert(pings.payload.data.study_state === "exit"); - }); - }); -}); diff --git a/test/utils.js b/test/utils.js deleted file mode 100644 index f06a237..0000000 --- a/test/utils.js +++ /dev/null @@ -1,90 +0,0 @@ -/* eslint-env node */ -// The geckodriver package downloads and installs geckodriver for us. -// We use it by requiring it. -require("geckodriver"); -// const assert = require("assert"); -const cmd = require("selenium-webdriver/lib/command"); -const firefox = require("selenium-webdriver/firefox"); -const Fs = require("fs-extra"); -const FxRunnerUtils = require("fx-runner/lib/utils"); -const path = require("path"); -const webdriver = require("selenium-webdriver"); - -// const By = webdriver.By; -const Context = firefox.Context; -// const until = webdriver.until; - -// Note: Geckodriver already has quite a good set of default preferences -// for disabling various items. -// https://github.com/mozilla/geckodriver/blob/master/src/marionette.rs -const FIREFOX_PREFERENCES = { - // Ensure e10s is turned on. - "browser.tabs.remote.autostart": true, - "browser.tabs.remote.autostart.1": true, - "browser.tabs.remote.autostart.2": true, - // These are good to have set up if you're debugging tests with the browser - // toolbox. - "devtools.chrome.enabled": true, - "devtools.debugger.remote-enabled": true, - "devtools.debugger.prompt-connection": false, - "general.warnOnAboutConfig": false -}; - -// useful if we need to test on a specific version of Firefox -async function promiseActualBinary(binary) { - try { - const normalizedBinary = await FxRunnerUtils.normalizeBinary(binary); - await Fs.stat(normalizedBinary); - return normalizedBinary; - } catch (ex) { - if (ex.code === "ENOENT") { - throw new Error(`Could not find ${binary}`); - } - throw ex; - } -} - -module.exports.promiseSetupDriver = async() => { - const profile = new firefox.Profile(); - - Object.keys(FIREFOX_PREFERENCES).forEach((key) => { - profile.setPreference(key, FIREFOX_PREFERENCES[key]); - }); - - const options = new firefox.Options(); - options.setProfile(profile); - - const builder = new webdriver.Builder() - .forBrowser("firefox") - .setFirefoxOptions(options); - - const binaryLocation = await promiseActualBinary(process.env.FIREFOX_BINARY || "firefox"); - await options.setBinary(new firefox.Binary(binaryLocation)); - const driver = await builder.build(); - driver.setContext(Context.CHROME); - return driver; -}; - -module.exports.installAddon = async(driver) => { - // references: - // https://bugzilla.mozilla.org/show_bug.cgi?id=1298025 - // https://github.com/mozilla/geckodriver/releases/tag/v0.17.0 - const fileLocation = path.join(process.cwd(), process.env.XPI_NAME); - const executor = driver.getExecutor(); - executor.defineCommand("installAddon", "POST", "/session/:sessionId/moz/addon/install"); - const installCmd = new cmd.Command("installAddon"); - - const session = await driver.getSession(); - installCmd.setParameters({ sessionId: session.getId(), path: fileLocation, temporary: true }); - return executor.execute(installCmd); -}; - -module.exports.uninstallAddon = async(driver, id) => { - const executor = driver.getExecutor(); - executor.defineCommand("uninstallAddon", "POST", "/session/:sessionId/moz/addon/uninstall"); - const uninstallCmd = new cmd.Command("uninstallAddon"); - - const session = await driver.getSession(); - uninstallCmd.setParameters({ sessionId: session.getId(), id }); - await executor.execute(uninstallCmd); -}; diff --git a/testUtils/executeJs.js b/testUtils/executeJs.js new file mode 100644 index 0000000..1e56acd --- /dev/null +++ b/testUtils/executeJs.js @@ -0,0 +1,91 @@ +/* eslint-env node */ + +const firefox = require("selenium-webdriver/firefox"); +const Context = firefox.Context; + +/** + * The tests rely on the add-on's background script opening up + * an extension page in a new window/tab. + * + * In background.js, make it possible for your tests to execute + * the following at some point: + * + * const createData = { + * type: "detached_panel", + * url: "extension-page-for-tests/index.html", + * width: 500, + * height: 500, + * }; + * browser.windows.create(createData); + * + * Extension pages get access to all the same privileged + * WebExtension APIs as the background scripts, allowing us + * to run tests directly against those APIs. + * + * This variable sets the expected path of this extension page so + * that we can check if we are in the right context to run tests. + * + * TODO: Find a cleaner way to accomplish this + * @type {string} + */ +const extensionPagePath = "/extension-page-for-tests/index.html"; + +module.exports.executeJs = { + /** + * Executes JavaScript with access to all the same privileged + * WebExtension APIs as the background scripts, allowing us + * to run tests directly against those APIs. + * + * @param driver + * @param callable + * @returns {Promise<*>} + */ + executeAsyncScriptInExtensionPageForTests: async (driver, callable) => { + driver.setContext(Context.CONTENT); + + const checkIfCurrentlyInExtensionPageWindow = async () => { + let currentUrl = await driver.getCurrentUrl(); + return currentUrl.indexOf(extensionPagePath) > 0; + }; + + const isCurrentlyInExtensionPageWindow = await checkIfCurrentlyInExtensionPageWindow(); + + // Wait for the extension page window to be available + // (we may still be loading firefox/the add-on) + if (!isCurrentlyInExtensionPageWindow) { + await driver.wait( + async function() { + const handles = await driver.getAllWindowHandles(); + return handles.length === 2; + }, + 9000, + "Should have opened a popup", + ); + + const handles = await driver.getAllWindowHandles(); + const currentHandle = await driver.getWindowHandle(); + + // Find the new window handle. + let newWindowHandle = null; + for (const handle of handles) { + if (handle !== currentHandle) { + newWindowHandle = handle; + } + } + + // Switch to the extension page popup + await driver.switchTo().window(newWindowHandle); + + // Check the tab has loaded the right page. + // We use driver.wait to wait for the page to be loaded, since we + // are not able to easily use the load listeners built into selenium. + await driver.wait( + checkIfCurrentlyInExtensionPageWindow, + 10000, + "Should have loaded the extension page for tests", + ); + } + + return await driver.executeAsyncScript(callable); + }, +}; diff --git a/testUtils/nav.js b/testUtils/nav.js new file mode 100644 index 0000000..75a7a40 --- /dev/null +++ b/testUtils/nav.js @@ -0,0 +1,13 @@ +/* eslint-env node */ + +const firefox = require("selenium-webdriver/firefox"); +const Context = firefox.Context; + +module.exports.nav = { + gotoURL: async (driver, url) => { + // navigate to a regular page + driver.setContext(Context.CONTENT); + await driver.get(url); + driver.setContext(Context.CHROME); + }, +}; diff --git a/testUtils/pings.js b/testUtils/pings.js new file mode 100644 index 0000000..52d095f --- /dev/null +++ b/testUtils/pings.js @@ -0,0 +1,100 @@ +/* eslint-env node */ + +module.exports.pings = { + /** Returns array of pings of type `type` in reverse sorted order by timestamp + * first element is most recent ping + * + * as seen in shield-study-addon-util's `utils.jsm` + * options + * - type: string or array of ping types + * - n: positive integer. at most n pings. + * - timestamp: only pings after this timestamp. + * - headersOnly: boolean, just the 'headers' for the pings, not the full bodies. + */ + getTelemetryPings: async (driver, passedOptions) => { + // callback is how you get the return back from the script + return driver.executeAsyncScript(async (options, callback) => { + let { type } = options; + const { n, timestamp, headersOnly } = options; + Components.utils.import("resource://gre/modules/TelemetryArchive.jsm"); + // {type, id, timestampCreated} + let pings = await TelemetryArchive.promiseArchivedPingList(); + if (type) { + if (!(type instanceof Array)) { + type = [type]; // Array-ify if it's a string + } + } + if (type) pings = pings.filter(p => type.includes(p.type)); + + if (timestamp) pings = pings.filter(p => p.timestampCreated > timestamp); + + pings.sort((a, b) => b.timestampCreated - a.timestampCreated); + if (n) pings = pings.slice(0, n); + const pingData = headersOnly + ? pings + : pings.map(ping => TelemetryArchive.promiseArchivedPingById(ping.id)); + + callback(await Promise.all(pingData)); + }, passedOptions); + }, + + getShieldPingsAfterTimestamp: async (driver, ts) => { + return getTelemetryPings(driver, { + type: ["shield-study", "shield-study-addon"], + timestamp: ts, + }); + }, + + summarizePings: pings => { + return pings.map(p => [p.payload.type, p.payload.data]); + }, + + pingsReport: async pings => { + if (pings.length === 0) { + return { report: "No pings found" }; + } + const p0 = pings[0].payload; + // print common fields + const report = + ` +// common fields + +branch ${p0.branch} +study_name ${p0.study_name} +addon_version ${p0.addon_version} +version ${p0.version} + +` + + pings + .map( + (p, i) => `${i} ${p.creationDate} ${p.payload.type} +${JSON.stringify(p.payload.data, null, 2)} + +`, + ) + .join("\n"); + + return { report }; + }, + + searchTelemetry: (conditionArray, telemetryArray) => { + const resultingPings = []; + for (const condition of conditionArray) { + const index = telemetryArray.findIndex(ping => condition(ping)); + if (index === -1) { + throw new this.SearchError(condition); + } + resultingPings.push(telemetryArray[index]); + } + return resultingPings; + }, + + SearchError: class extends Error { + constructor(condition) { + const message = `Could not find ping satisfying condition: ${condition.toString()}`; + super(message); + this.message = message; + this.name = "SearchError"; + } + }, +}; diff --git a/testUtils/setup.js b/testUtils/setup.js new file mode 100644 index 0000000..44948d3 --- /dev/null +++ b/testUtils/setup.js @@ -0,0 +1,94 @@ +/* eslint-env node */ + +const cmd = require("selenium-webdriver/lib/command"); +const firefox = require("selenium-webdriver/firefox"); +const webdriver = require("selenium-webdriver"); +const FxRunnerUtils = require("fx-runner/lib/utils"); +const Fs = require("fs-extra"); +const path = require("path"); +const Context = firefox.Context; + +// useful if we need to test on a specific version of Firefox +async function promiseActualBinary(binary) { + try { + let normalizedBinary = await FxRunnerUtils.normalizeBinary(binary); + normalizedBinary = path.resolve(normalizedBinary); + await Fs.stat(normalizedBinary); + return normalizedBinary; + } catch (ex) { + if (ex.code === "ENOENT") { + throw new Error(`Could not find ${binary}`); + } + throw ex; + } +} + +module.exports.setup = { + /** + * Uses process.env.FIREFOX_BINARY + */ + promiseSetupDriver: async FIREFOX_PREFERENCES => { + const profile = new firefox.Profile(); + + // TODO, allow 'actually send telemetry' here. + Object.keys(FIREFOX_PREFERENCES).forEach(key => { + profile.setPreference(key, FIREFOX_PREFERENCES[key]); + }); + + // TODO glind, allow config to re-use profile + const options = new firefox.Options(); + options.setProfile(profile); + + const builder = new webdriver.Builder() + .forBrowser("firefox") + .setFirefoxOptions(options); + + const binaryLocation = await promiseActualBinary( + process.env.FIREFOX_BINARY || "firefox", + ); + await options.setBinary(new firefox.Binary(binaryLocation)); + const driver = await builder.build(); + // Firefox will be started up by now + driver.setContext(Context.CHROME); + return driver; + }, + + installAddon: async (driver, fileLocation) => { + // references: + // https://bugzilla.mozilla.org/show_bug.cgi?id=1298025 + // https://github.com/mozilla/geckodriver/releases/tag/v0.17.0 + fileLocation = + fileLocation || path.join(process.cwd(), process.env.ADDON_ZIP); + + const executor = driver.getExecutor(); + executor.defineCommand( + "installAddon", + "POST", + "/session/:sessionId/moz/addon/install", + ); + const installCmd = new cmd.Command("installAddon"); + + const session = await driver.getSession(); + installCmd.setParameters({ + sessionId: session.getId(), + path: fileLocation, + temporary: true, + }); + await executor.execute(installCmd); + console.log(`Add-on at ${fileLocation} installed`); + }, + + uninstallAddon: async (driver, id) => { + const executor = driver.getExecutor(); + executor.defineCommand( + "uninstallAddon", + "POST", + "/session/:sessionId/moz/addon/uninstall", + ); + const uninstallCmd = new cmd.Command("uninstallAddon"); + + const session = await driver.getSession(); + uninstallCmd.setParameters({ sessionId: session.getId(), id }); + await executor.execute(uninstallCmd); + }, +}; diff --git a/testUtils/ui.js b/testUtils/ui.js new file mode 100644 index 0000000..e397c0b --- /dev/null +++ b/testUtils/ui.js @@ -0,0 +1,120 @@ +/* eslint-env node */ + +const webdriver = require("selenium-webdriver"); +const firefox = require("selenium-webdriver/firefox"); +const Context = firefox.Context; +const until = webdriver.until; + +/* Firefox UI testing helper functions */ +module.exports.ui = { + promiseManifest: async () => { + const manifestJson = await Fs.readFile( + path.resolve("src/manifest.json"), + "utf8", + ); + return JSON.parse(manifestJson); + }, + + /** + * The widget id is used to identify add-on specific chrome elements. Examples: + * - Browser action - {addonWidgetId}-browser-action + * - Page action - {addonWidgetId}-page-action + * Search for makeWidgetId(extension.id) in the Firefox source code for more examples. + * @returns {Promise<*>} + */ + addonWidgetId: async () => { + /** + * From firefox/browser/components/extensions/ExtensionPopups.jsm + */ + function makeWidgetId(id) { + id = id.toLowerCase(); + // FIXME: This allows for collisions. + return id.replace(/[^a-z0-9_-]/g, "_"); + } + + const manifest = await promiseManifest(); + return makeWidgetId(manifest.applications.gecko.id); + }, + + takeScreenshot: async (driver, filepath = "./screenshot.png") => { + try { + const data = await driver.takeScreenshot(); + return await Fs.outputFile(filepath, data, "base64"); + } catch (screenshotError) { + throw screenshotError; + } + }, + + MODIFIER_KEY: (function getModifierKey() { + const modifierKey = + process.platform === "darwin" + ? webdriver.Key.COMMAND + : webdriver.Key.CONTROL; + return modifierKey; + })(), + + // TODO glind, this interface feels janky + // this feels like it wants to be $ like. + // not obvious right now, moving on! + getChromeElementBy: class { + static async _get1(driver, method, selector) { + driver.setContext(Context.CHROME); + try { + return await driver.wait( + until.elementLocated(By[method](selector)), + 1000, + ); + } catch (e) { + // if there an error, the button was not found + console.error(e); + return null; + } + } + + static async id(driver, id) { + return this._get1(driver, "id", id); + } + + static async className(driver, className) { + return this._get1(driver, "className", className); + } + + static async tagName(driver, tagName) { + return this._get1(driver, "tagName", tagName); + } + }, + + promiseUrlBar: driver => { + driver.setContext(Context.CHROME); + return driver.wait(until.elementLocated(By.id("urlbar")), 1000); + }, + + // such as: "social-share-button" + addButtonFromCustomizePanel: async (driver, buttonId) => + driver.executeAsyncScript(callback => { + // see https://dxr.mozilla.org/mozilla-central/rev/211d4dd61025c0a40caea7a54c9066e051bdde8c/browser/base/content/browser-social.js#193 + Components.utils.import("resource:///modules/CustomizableUI.jsm"); + CustomizableUI.addWidgetToArea(buttonId, CustomizableUI.AREA_NAVBAR); + callback(); + }), + + removeButtonFromNavbar: async (driver, buttonId) => { + driver.setContext(Context.CONTENT); + try { + await driver.executeAsyncScript(callback => { + Components.utils.import("resource:///modules/CustomizableUI.jsm"); + CustomizableUI.removeWidgetFromArea(buttonId); + callback(); + }); + + // TODO glind fix this, I think this is supposed to prove it's dead. + const button = await this.promiseAddonButton(driver); + return button === null; + } catch (e) { + if (e.name === "TimeoutError") { + return false; + } + throw e; + } + }, +}; diff --git a/testUtils/wip.js b/testUtils/wip.js new file mode 100644 index 0000000..5ccdcca --- /dev/null +++ b/testUtils/wip.js @@ -0,0 +1,98 @@ +/* eslint-env node */ +/* eslint no-console:off */ + +const firefox = require("selenium-webdriver/firefox"); +const Context = firefox.Context; +const until = webdriver.until; + +// TODO glind general wrapper for 'async with callback'? + +/* this is NOT WORKING FOR UNKNOWN HARD TO EXLAIN REASONS +=> Uncaught WebDriverError: InternalError: too much recursion +module.exports.allAddons = async(driver) => { + // callback is how you get the return back from the script + return driver.executeAsyncScript(async(callback,) => { + Components.utils.import("resource://gre/modules/AddonManager.jsm"); + const L = await AddonManager.getAllAddons(); + callback(await L); + }); +}; +*/ + +// TODO glind, specific to share-button-study but useful to demo patterns. +// TODO glind, generalize, document, or destroy + +// module.exports.copyUrlBar = async(driver) => { +// const urlBar = await getChromeElementBy.id(driver,'urlbar'); +// const urlBar = await module.exports.promiseUrlBar(driver); +// await urlBar.sendKeys(webdriver.Key.chord(MODIFIER_KEY, "A")); +// await urlBar.sendKeys(webdriver.Key.chord(MODIFIER_KEY, "C")); +// }; + +// module.exports.testAnimation = async(driver) => { +// const button = await module.exports.promiseAddonButton(driver); +// if (button === null) { return { hasClass: false, hasColor: false }; } +// +// const buttonClassString = await button.getAttribute("class"); +// const buttonColor = await button.getCssValue("background-color"); +// +// const hasClass = buttonClassString.split(" ").includes("social-share-button-on"); +// const hasColor = buttonColor.includes("43, 153, 255"); +// return { hasClass, hasColor }; +// }; + +// module.exports.waitForClassAdded = async(driver) => { +// try { +// const animationTest = await driver.wait(async() => { +// const { hasClass } = await module.exports.testAnimation(driver); +// return hasClass; +// }, 1000); +// return animationTest; +// } catch (e) { +// if (e.name === "TimeoutError") { return null; } +// throw (e); +// } +// }; +// +// module.exports.waitForAnimationEnd = async(driver) => { +// try { +// return await driver.wait(async() => { +// const { hasClass, hasColor } = await module.exports.testAnimation(driver); +// return !hasClass && !hasColor; +// }, 1000); +// } catch (e) { +// if (e.name === "TimeoutError") { return null; } +// throw (e); +// } +// }; + +// module.exports.testPanel = async(driver, panelId) => { +// driver.setContext(Context.CHROME); +// try { // if we can't find the panel, return false +// return await driver.wait(async() => { +// // need to execute JS, since state is not an HTML attribute, it's a property +// const panelState = await driver.executeAsyncScript((panelIdArg, callback) => { +// const shareButtonPanel = window.document.getElementById(panelIdArg); +// if (shareButtonPanel === null) { +// callback(null); +// } else { +// const state = shareButtonPanel.state; +// callback(state); +// } +// }, panelId); +// return panelState === "open"; +// }, 1000); +// } catch (e) { +// if (e.name === "TimeoutError") { return null; } +// throw e; +// } +// }; + +// module.exports.closePanel = async(driver, target = null) => { +// if (target !== null) { +// target.sendKeys(webdriver.Key.ESCAPE); +// } else { +// const urlbar = await module.exports.promiseUrlBar(driver); +// await urlbar.sendKeys(webdriver.Key.ESCAPE); +// } +// }; diff --git a/webExtensionApis/prefs/api.js b/webExtensionApis/prefs/api.js new file mode 100644 index 0000000..aef5915 --- /dev/null +++ b/webExtensionApis/prefs/api.js @@ -0,0 +1,50 @@ +"use strict"; + +ChromeUtils.import("resource://gre/modules/Services.jsm"); + +const PREFERENCES_PREFIX = ""; + +function get(key, type = "char") { + key = PREFERENCES_PREFIX + key; + + switch (type) { + case "char": + return Services.prefs.getCharPref(key); + case "bool": + return Services.prefs.getBoolPref(key); + case "int": + return Services.prefs.getIntPref(key); + } + + throw new Error(`Unknown type: ${type}`); +} + +function set(key, type, value) { + key = PREFERENCES_PREFIX + key; + + switch (type) { + case "char": + return Services.prefs.setCharPref(key, value); + case "bool": + return Services.prefs.setBoolPref(key, value); + case "int": + return Services.prefs.setIntPref(key, value); + } + throw new Error(`Unknown type: ${type}`); +} + +/* https://firefox-source-docs.mozilla.org/toolkit/components/extensions/webextensions/functions.html */ +this.prefs = class extends ExtensionAPI { + getAPI(context) { + return { + prefs: { + async get(prefName) { + return "getting"; + }, + async set(prefName, value) { + return "set"; + }, + }, + }; + } +}; diff --git a/webExtensionApis/prefs/schema.json b/webExtensionApis/prefs/schema.json new file mode 100644 index 0000000..605c449 --- /dev/null +++ b/webExtensionApis/prefs/schema.json @@ -0,0 +1,36 @@ +[ + { + "namespace": "prefs", + "description": "Pref get, set, watch, unwatch(?)", + "functions": [ + { + "name": "get", + "type": "function", + "description": "Returns the value of a pref", + "async": true, + "parameters": [ + { + "name": "prefName", + "type": "string" + } + ] + }, + { + "name": "set", + "type": "function", + "description": "Sets the value of a pref", + "async": true, + "parameters": [ + { + "name": "prefName", + "type": "string" + }, + { + "name": "value", + "type": "any" + } + ] + } + ] + } +] diff --git a/webExtensionApis/study/.gitignore b/webExtensionApis/study/.gitignore new file mode 100644 index 0000000..2e3f83a --- /dev/null +++ b/webExtensionApis/study/.gitignore @@ -0,0 +1 @@ +/api.js diff --git a/webExtensionApis/study/schema.json b/webExtensionApis/study/schema.json new file mode 100644 index 0000000..1807617 --- /dev/null +++ b/webExtensionApis/study/schema.json @@ -0,0 +1,76 @@ +[ + { + "namespace": "study", + "description": "study", + "functions": [ + { + "name": "configure", + "type": "function", + "description": "TODO", + "async": true, + "parameters": [ + { + "name": "studySetup", + "type": "any" + } + ] + }, + { + "name": "deterministicVariation", + "type": "function", + "description": "TODO", + "async": true, + "parameters": [ + { + "name": "weightedVariations", + "type": "any" + }, + { + "optional": true, + "name": "fraction", + "type": "any" + } + ] + }, + { + "name": "startup", + "type": "function", + "description": "TODO", + "async": true, + "parameters": [] + }, + { + "name": "info", + "type": "function", + "description": "TODO", + "async": true, + "parameters": [] + }, + { + "name": "telemetry", + "type": "function", + "description": "TODO", + "async": true, + "parameters": [ + { + "name": "data", + "type": "any" + } + ] + }, + { + "name": "endStudy", + "type": "function", + "description": "TODO", + "async": true, + "parameters": [ + { + "optional": true, + "name": "data", + "type": "any" + } + ] + } + ] + } +] diff --git a/webExtensionApis/study/src/index.js b/webExtensionApis/study/src/index.js new file mode 100644 index 0000000..53ddf6b --- /dev/null +++ b/webExtensionApis/study/src/index.js @@ -0,0 +1,122 @@ +/* eslint-env commonjs */ + +/* global ExtensionAPI */ + +this.study = class extends ExtensionAPI { + /** + * We don't need to override the constructor for other + * reasons than to clarify the class member "extension" + * being of type Extension + * + * @param extension Extension + */ + constructor(extension) { + super(extension); + /** + * @type Extension + */ + this.extension = extension; + } + + /** + * Extension Shutdown + * APIs that allocate any resources (e.g., adding elements to the browser’s + * user interface, setting up internal event listeners, etc.) must free + * these resources when the extension for which they are allocated is + * shut down. + */ + onShutdown(shutdownReason) { + console.log("onShutdown", shutdownReason); + // TODO: debootstrap study + } + + getAPI(context) { + const { studyUtils } = require("./studyUtils.js"); + const studyUtilsBootstrap = require("./studyUtilsBootstrap.js"); + // const { PioneerUtils } = require("pioneer-utils/PioneerUtils.jsm"); + // const pioneerUtilsBootstrap = require("./pioneerUtilsBootstrap.js"); + + let bootstrap; + + const { extension } = this; + + return { + study: { + /** + * ensure we have configured study + * and are supposed to run our feature + * @returns {Promise} + */ + async configure(studySetup) { + bootstrap = studyUtilsBootstrap.Bootstrap(studySetup, studyUtils); + await bootstrap.configure(extension); + }, + + async startup() { + await bootstrap.startup(extension); + }, + + async deterministicVariation(weightedVariations, fraction) { + if (typeof fraction === "string") { + fraction = parseFloat(fraction); + } + return await studyUtils.deterministicVariation( + weightedVariations, + fraction, + ); + }, + + /** + * current studyUtils configuration, including 'variation' + * @returns {Promise} + */ + async info() { + return studyUtils.info(); + }, + + /** + * + * `telemetry` + * + * - check all pings for validity as "shield-study-addon" pings + * - send a 'shield-study-addon' packet + * + * Good practice: send all Telemetry from one function for easier + * logging, debugging, validation + * + * Note: keys, values must be strings to fulfill the + * `shield-study-addon` ping-type validation. + * This allows `payload.data.attributes` to store + * correctly at Parquet at s.t.m.o. + * + * Bold claim: catching errors here + * + */ + async telemetry(data) { + function throwIfInvalid(obj) { + // Check: all keys and values must be strings, + for (const k in obj) { + if (typeof k !== "string") + throw new Error(`key ${k} not a string`); + if (typeof obj[k] !== "string") + throw new Error(`value ${k} ${obj[k]} not a string`); + } + return true; + } + + throwIfInvalid(data); + studyUtils.telemetry(data); + }, + + /** + * for ending a study + * @param data + * @returns {Promise} + */ + async endStudy(data) { + studyUtils.endStudy(data); + }, + }, + }; + } +}; diff --git a/webExtensionApis/study/src/jsonschema.js b/webExtensionApis/study/src/jsonschema.js new file mode 100644 index 0000000..45b44a9 --- /dev/null +++ b/webExtensionApis/study/src/jsonschema.js @@ -0,0 +1,31 @@ +const Ajv = require("ajv/dist/ajv.min.js"); +const ajv = new Ajv(); + +const jsonschema = { + /** + * Validates input data based on a specified schema + * @param {Object} data - The data to be validated + * @param {Object} schema - The schema to validate against + * @returns {boolean} - Will return true if the data is valid + */ + validate(data, schema) { + const valid = ajv.validate(schema, data); + return { valid, errors: ajv.errors || [] }; + }, + /** + * Validates input data based on a specified schema + * @param {Object} data - The data to be validated + * @param {Object} schema - The schema to validate against + * @throws Will throw an error if the data is not valid + * @returns {boolean} - Will return true if the data is valid + */ + validateOrThrow(data, schema) { + const valid = ajv.validate(schema, data); + if (!valid) { + throw new Error(JSON.stringify(ajv.errors)); + } + return true; + }, +}; + +export default jsonschema; diff --git a/webExtensionApis/study/src/sampling.js b/webExtensionApis/study/src/sampling.js new file mode 100644 index 0000000..027ab19 --- /dev/null +++ b/webExtensionApis/study/src/sampling.js @@ -0,0 +1,105 @@ +import jsonschema from "./jsonschema"; +import schemas from "./schemas"; + +const { utils: Cu } = Components; +Cu.import("resource://gre/modules/Services.jsm"); +const { TextEncoder } = Cu.getGlobalForObject(Services); + +/** + * Given sample weights (weightedVariations) and a particular position + * (fraction), return a variation. If no fraction given, return a variation + * at random fraction proportional to the weightVariations object + * @param {Object[]} weightedVariations - the array of branch name:weight pairs + * used to randomly assign the user to a branch + * @param {Number} fraction - a number (0 <= fraction < 1) + * @returns {Object} - the variation object in weightedVariations for the given + * fraction + */ +export function chooseWeighted(weightedVariations, fraction = Math.random()) { + /* + weightedVaiations, list of: + { + name: string of any length + weight: float >= 0 + } + */ + jsonschema.validateOrThrow(weightedVariations, schemas.weightedVariations); + + const weights = weightedVariations.map(x => x.weight || 1); + const partial = cumsum(weights); + const total = weights.reduce((a, b) => a + b); + for (let ii = 0; ii < weightedVariations.length; ii++) { + if (fraction <= partial[ii] / total) { + return weightedVariations[ii]; + } + } + return null; +} + +/** + * @async + * Converts a string into a fraction (0 <= fraction < 1) based on the first + * X bits of its sha256 hexadecimal representation + * Note: Salting (adding the study name to the telemetry clientID) ensures + * that the same user gets a different bucket/hash for each study. + * Hashing of the salted string ensures uniform hashing; i.e. that every + * bucket/variation gets filled. + * @param {string} saltedString - a salted string used to create a hash for + * the user + * @param {Number} bits - The first number of bits to use in the sha256 hex + * representation + * @returns {Number} - a fraction (0 <= fraction < 1) + */ +export async function hashFraction(saltedString, bits = 12) { + const hash = await sha256(saltedString); + return parseInt(hash.substr(0, bits), 16) / Math.pow(16, bits); +} + +/** + * @async + * Converts a string into its sha256 hexadecimal representation. + * Note: This is ultimately used to make a hash of the user's telemetry clientID + * and the study name. + * @param {string} message - The message to convert. + * @returns {string} - a hexadecimal, 256-bit hash + */ +export async function sha256(message) { + // encode as UTF-8 + const msgBuffer = new TextEncoder("utf-8").encode(message); + // hash the message + const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer); + // convert ArrayBuffer to Array + const hashArray = Array.from(new Uint8Array(hashBuffer)); + // convert bytes to hex string + const hashHex = hashArray + .map(b => ("00" + b.toString(16)).slice(-2)) + .join(""); + return hashHex; +} + +/** + * Converts an array of length N into a cumulative sum array of length N, + * where n_i = sum(array.slice(0,i)) i.e. each element is the sum of all + * elements up to and including that element + * This is ultimately used for turning sample weights (AKA weightedVariations) + * into right hand limits (>= X) to deterministically select which variation + * a user receives. + * @example [.25,.3,.45] => [.25,.55,1.0]; if a user's sample weight were .25, + * they would fall into the left-most bucket + * @param {Number[]} arr - An array of sample weights (0 <= sample weight < 1) + * @returns {Number[]} - A cumulative sum array of sample weights + * (0 <= sample weight <= 1) + */ +export function cumsum(arr) { + return arr.reduce(function(r, c, i) { + r.push((r[i - 1] || 0) + c); + return r; + }, []); +} + +export default { + chooseWeighted, + cumsum, + hashFraction, + sha256, +}; diff --git a/webExtensionApis/study/src/schemas/index.js b/webExtensionApis/study/src/schemas/index.js new file mode 100644 index 0000000..9ab0a98 --- /dev/null +++ b/webExtensionApis/study/src/schemas/index.js @@ -0,0 +1,9 @@ +/* eslint-env commonjs */ + +module.exports = { + "shield-study": require("shield-study-schemas/schemas-client/shield-study.schema.json"), // eslint-disable-line max-len + "shield-study-addon": require("shield-study-schemas/schemas-client/shield-study-addon.schema.json"), // eslint-disable-line max-len + "shield-study-error": require("shield-study-schemas/schemas-client/shield-study-error.schema.json"), // eslint-disable-line max-len + studySetup: require("./schema.studySetup.json"), + weightedVariations: require("./schema.weightedVariations.json"), +}; diff --git a/src/schema.studySetup.json b/webExtensionApis/study/src/schemas/schema.studySetup.json similarity index 69% rename from src/schema.studySetup.json rename to webExtensionApis/study/src/schemas/schema.studySetup.json index a061b96..cb90023 100644 --- a/src/schema.studySetup.json +++ b/webExtensionApis/study/src/schemas/schema.studySetup.json @@ -1,10 +1,10 @@ { "$schema": "http://json-schema.org/draft-04/schema#", - "title": "study setup", + "title": "study setup", "type": "object", "definitions": { "idString": { - "description": "between 1,100 chars, no spaces, unicode ok.", + "description": "between 1,100 chars, no spaces, unicode ok.", "type": "string", "pattern": "^\\S+$", "minLength": 1, @@ -27,12 +27,23 @@ }, "study_state_fullname": { "type": "string", - "description": "Second part of name of state, if any. Study-specific for study-defined endings." + "description": + "Second part of name of state, if any. Study-specific for study-defined endings." }, "url": { "type": "string" } } + }, + "variation": { + "name": { + "type": "string" + }, + "weight": { + "type": "number", + "minimum": 0 + }, + "required": ["name", "weight"] } }, "properties": { @@ -60,23 +71,19 @@ }, "onInvalid": { "type": "string", - "enum": [ - "throw", - "log" - ] + "enum": ["throw", "log"] } }, - "required": [ - "removeTestingFlag", - "send" - ] + "required": ["removeTestingFlag", "send"] } }, - "required": [ - "studyName", - "endings", - "telemetry" - ] + "required": ["studyName", "endings", "telemetry"] + }, + "weightedVariations": { + "items": { + "$ref": "#/definitions/variation" + }, + "type": "array" }, "addon": { "type": "object", @@ -90,14 +97,8 @@ "description": "Semantic version of the addon." } }, - "required": [ - "id", - "version" - ] + "required": ["id", "version"] } }, - "required": [ - "study", - "addon" - ] -} \ No newline at end of file + "required": ["study", "weightedVariations", "addon"] +} diff --git a/src/schema.weightedVariations.json b/webExtensionApis/study/src/schemas/schema.weightedVariations.json similarity index 83% rename from src/schema.weightedVariations.json rename to webExtensionApis/study/src/schemas/schema.weightedVariations.json index f6b7cd5..3c7c809 100644 --- a/src/schema.weightedVariations.json +++ b/webExtensionApis/study/src/schemas/schema.weightedVariations.json @@ -9,10 +9,7 @@ "type": "number", "minimum": 0 }, - "required": [ - "name", - "weight" - ] + "required": ["name", "weight"] } }, "items": { diff --git a/webExtensionApis/study/src/studyUtils.js b/webExtensionApis/study/src/studyUtils.js new file mode 100644 index 0000000..d5fc9ba --- /dev/null +++ b/webExtensionApis/study/src/studyUtils.js @@ -0,0 +1,724 @@ +/* eslint-env commonjs */ + +"use strict"; + +import sampling from "./sampling"; + +/* +* For an overview of what this module does, see ABOUT.md at +* github.com/mozilla/shield-studies-addon-template +* +* Note: There are a number of methods that won't work if the +* setup method has not executed (they perform a check with the +* `throwIfNotSetup` method). The setup method ensures that the +* studySetup data passed in is valid per the studySetup schema. +*/ + +/* +* TODO glind survey / urls & query args +* TODO glind publish as v4 +*/ +const EXPORTED_SYMBOLS = ["studyUtils"]; + +const UTILS_VERSION = require("../../../package.json").version; +const PACKET_VERSION = 3; + +const { utils: Cu } = Components; +Cu.import("resource://gre/modules/AddonManager.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.importGlobalProperties(["URL", "crypto", "URLSearchParams"]); + +let log; +const studyUtilsLoggingLevel = "Trace"; // Fatal: 70, Error: 60, Warn: 50, Info: 40, Config: 30, Debug: 20, Trace: 10, All: -1, + +// telemetry utils +const CID = Cu.import("resource://gre/modules/ClientID.jsm", null); +const { TelemetryController } = Cu.import( + "resource://gre/modules/TelemetryController.jsm", + null, +); +const { TelemetryEnvironment } = Cu.import( + "resource://gre/modules/TelemetryEnvironment.jsm", + null, +); + +/* +* Set-up JSON schema validation +* Schemas are used to validate an input (here, via AJV at runtime) +* Schemas here are used for: +* - Telemetry (Ensure correct Parquet format for different types of +* outbound packets): +* - "shield-study": shield study state and outcome data common to all +* shield studies. +* - "shield-study-addon": addon-specific probe data, with `attributes` +* (used to capture feature-specific state) sent as Map(string,string). +* - "shield-study-error": data used to notify, group and count some kinds +* of errors from shield studies +* - ShieldUtils API ducktypes: +* - "weightedVariations": the array of branch name:weight pairs used to +* randomly assign the user +* to a branch +* - "webExtensionMsg": the message object passed into the +* StudyUtils.respondToWebExtensionMessage method +* - "studySetup": the options object passed into the StudyUtils.setup method +*/ +import schemas from "./schemas"; +import jsonschema from "./jsonschema"; + +/** + * Note: This is the deep merge from the addon-sdk (sdk/util/object.js). + * Probably deeper than we need. Unlike the shallow merge with the + * spread operator (const c = {...a, ...b}), this function can be configured + * to copy non-enumerable properties, symbols, and property descriptors. + * + * Merges all the properties of all arguments into first argument. If two or + * more argument objects have own properties with the same name, the property + * is overridden, with precedence from right to left, implying, that properties + * of the object on the left are overridden by a same named property of the + * object on the right. + * + * Any argument given with "falsy" value - commonly `null` and `undefined` in + * case of objects - are skipped. + * + * @examples + * var a = { bar: 0, a: 'a' } + * var b = merge(a, { foo: 'foo', bar: 1 }, { foo: 'bar', name: 'b' }); + * b === a // true + * b.a // 'a' + * b.foo // 'bar' + * b.bar // 1 + * b.name // 'b' + * + * @param {...Object} source - two or more object arguments + * @returns {Object} - the resulting merged object + */ +function merge(source) { + const optionsDefault = { + names: true, + symbols: true, + nonEnumerables: true, + }; + /** + * Gets object's own property symbols and/or names, including non-enumerables + * by default + * @param {Object} object - the object for which to get own property symbols + * and names + * @param {Object} options - object indicating what kinds of properties to + * merge + * @param {boolean} options.name - True if function should return object's own + * property names + * @param {boolean} options.symbols - True if function should return + * object's own property symbols + * @param {boolean} options.nonEnumerables - True if function should return + * object's non-enumerable own property names + * @returns {string[]|symbol[]} - An array of own property names and/or + * symbols for object + */ + function getOwnPropertyIdentifiers(object, options = optionsDefault) { + const symbols = !options.symbols + ? [] + : Object.getOwnPropertySymbols(object); + + // eslint-disable-next-line + const names = !options.names + ? [] + : options.nonEnumerables + ? Object.getOwnPropertyNames(object) + : Object.keys(object); + return [...names, ...symbols]; + } + /* + * descriptor: an object whose own enumerable properties constitute descriptors + * for the properties from arguments[1]+ to be defined or modified in + * arguments[0] + */ + const descriptor = {}; + /* + * `Boolean` converts the first parameter to a boolean value. Any object is + * converted to `true` where `null` and `undefined` becames `false`. Therefore + * the `filter` method will keep only objects that are defined and not null. + */ + Array.slice(arguments, 1) + .filter(Boolean) + .forEach(properties => { + getOwnPropertyIdentifiers(properties).forEach(name => { + descriptor[name] = Object.getOwnPropertyDescriptor(properties, name); + }); + }); + return Object.defineProperties(source, descriptor); +} + +/** + * Appends a query string to a url. + * @param {string} url - a base url to append; must be static (data) or external + * @param {Object} args - query arguments, one or more object literal used to + * build a query string + * @returns {string} - an absolute url appended with a query string + */ +function mergeQueryArgs(url, ...args) { + // currently left to right + // TODO, glind, decide order of merge here + // TODO, use Object.assign, or ES7 spread + const U = new URL(url); + // get the query string already attached to url, if it exists + let q = U.search || "?"; + // create an interface to interact with the query string + q = new URLSearchParams(q); + const merged = merge({}, ...args); + // Set each search parameter in "merged" to its value in the query string, + // building up the query string one search parameter at a time. + Object.keys(merged).forEach(k => { + // k, the search parameter (ex: fxVersion) + // q.get(k), returns the value of k, in query string, q (ex: 57.0.1a) + log.debug(q.get(k), k, merged[k]); + q.set(k, merged[k]); + }); + // append our new query string to the URL object made with "url" + U.search = q.toString(); + // return the full url, with the appended query string + return U.toString(); +} + +/** + * Class representing utilities for shield studies. + */ +class StudyUtils { + /** + * Create a StudyUtils instance. + */ + constructor() { + /* + * TODO glind Answer: no. see if you can merge the construtor and setup + * and export the class, rather than a singleton + */ + /** + * Handles a message received by the webExtension, sending a response back. + * @param {Object} webExtensionMsg object, see its schema + * @param {boolean} webExtensionMsg.shield - Whether or not the message + * is a shield message (intended for StudyUtils) + * @param {string} webExtensionMsg.msg - StudyUtils method to be called + *from the webExtension + * @param {*} webExtensionMsg.data - Data sent from webExtension + * @param {Object} sender - Details about the message sender, see + * runtime.onMessage MDN docs + * @param {responseCallback} sendResponse - The callback to send a response + * back to the webExtension + * @returns {boolean|undefined} - true if the message has been processed + * (shield message) or ignored (non-shield message) + */ + this.respondToWebExtensionMessage = function( + { shield, msg, data }, + sender, + sendResponse, + ) { + // @TODO glind: make sure we're using the webExtensionMsg schema + if (!shield) return true; + const allowedMethods = ["endStudy", "telemetry", "info"]; + if (!allowedMethods.includes(msg)) { + const errStr1 = "respondToWebExtensionMessage:"; + const errStr2 = "is not in allowed studyUtils methods:"; + throw new Error(`${errStr1} "${msg}" ${errStr2} ${allowedMethods}`); + } + /* + * handle async + * Execute the StudyUtils method requested by the webExtension + * then send the webExtension a response with their return value + */ + Promise.resolve(this[msg](data)).then( + function(ans) { + log.debug("respondingTo", msg, ans); + sendResponse(ans); + }, + // function error eventually + ); + return true; + /* Ensure this method is bound to the instance of studyUtils, see + * callsite in bootstrap.js + * TODO glind: bdanforth's claim: making this function a StudyUtils + * method would also do this. + */ + }.bind(this); + + /* + * Expose sampling methods onto the exported studyUtils singleton, for use + * by any Components.utils-importing module + */ + this.sampling = sampling; + + // expose schemas + this.schemas = schemas; + + // expose validation methods + this.jsonschema = jsonschema; + + this.REASONS = REASONS; + } + + /** + * Checks if the StudyUtils.setup method has been called + * @param {string} name - the name of a StudyUtils method + * @returns {void} + */ + throwIfNotSetup(name = "unknown") { + if (!this._isSetup) + throw new Error( + name + ": this method can't be used until `setup` is called", + ); + } + + /** + * Validates the studySetup object passed in from the addon. + * @param {Object} studySetup - the studySetup object, see schema.studySetup.json + * @returns {StudyUtils} - the StudyUtils class instance + */ + setup(studySetup) { + log = createLog("shield-study-utils", studyUtilsLoggingLevel); + log.debug("setting up!"); + jsonschema.validateOrThrow(studySetup, schemas.studySetup); + this.studySetup = studySetup; + this._isSetup = true; + return this; + } + + /** + * Resets the state of the study. Suggested use is for testing. + * @returns {void} + */ + reset() { + this.studySetup = {}; + delete this._variation; + this._isSetup = false; + } + + /** + * @async + * Opens a new tab that loads a page with the specified URL. + * @param {string} url - the url of a page + * @param {Object} params - optional, see + * https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Method/addTab + * @returns {void} + */ + async openTab(url, params = {}) { + this.throwIfNotSetup("openTab"); + log.debug(url, params); + log.debug("opening this formatted tab", url, params); + if (!Services.wm.getMostRecentWindow("navigator:browser").gBrowser) { + /* + * Automated tests run faster than Firefox opens windows. + * TODO: Find less gross way to do this + * Wait for the window to be opened + */ + await new Promise(resolve => setTimeout(resolve, 30000)); + } + Services.wm + .getMostRecentWindow("navigator:browser") + .gBrowser.addTab(url, params); + } + + /** + * @async + * Gets the telemetry client ID for the user. + * @returns {string} - the telemetry client ID + */ + async getTelemetryId() { + const id = TelemetryController.clientID; + /* istanbul ignore next */ + if (id === undefined) { + return await CID.ClientIDImpl._doLoadClientID(); + } + return id; + } + + /** + * Sets the variation for the StudyUtils instance. + * @param {Object} variation - the study variation for this user + * @returns {StudyUtils} - the StudyUtils class instance + */ + setVariation(variation) { + this.throwIfNotSetup("setVariation"); + this._variation = variation; + return this; + } + + /** + * Gets the variation for the StudyUtils instance. + * @returns {Object} - the study variation for this user + */ + getVariation() { + this.throwIfNotSetup("getvariation"); + return this._variation; + } + + /** + * @async + * Deterministically selects and returns the study variation for the user. + * @param {Object[]} weightedVariations - see schema.weightedVariations.json + * @param {Number} fraction - a number (0 <= fraction < 1); can be set explicitly for testing + * @returns {Object} - the study variation for this user + */ + async deterministicVariation(weightedVariations, fraction = null) { + console.log("deterministicVariation", arguments); + // this is the standard arm choosing method + if (fraction === null) { + // hash the studyName and telemetryId to get the same branch every time. + this.throwIfNotSetup("deterministicVariation needs studyName"); + const clientId = await this.getTelemetryId(); + const studyName = this.studySetup.study.studyName; + fraction = await this.sampling.hashFraction(studyName + clientId, 12); + } + return this.sampling.chooseWeighted(weightedVariations, fraction); + } + + /** + * Gets the Shield recipe client ID. + * @returns {string} - the Shield recipe client ID. + */ + getShieldId() { + const key = "extensions.shield-recipe-client.user_id"; + return Services.prefs.getCharPref(key, ""); + } + + /** + * Packages information about the study into an object. + * @returns {Object} - study information, see schema.studySetup.json + */ + info() { + log.debug("getting info"); + this.throwIfNotSetup("info"); + return { + studyName: this.studySetup.study.studyName, + addon: this.studySetup.addon, + variation: this.getVariation(), + shieldId: this.getShieldId(), + }; + } + + /** + * Get the telemetry configuration for the study. + * @returns {Object} - the telemetry cofiguration, see schema.studySetup.json + */ + // TODO glind, maybe this is getter / setter? + get telemetryConfig() { + this.throwIfNotSetup("telemetryConfig"); + return this.studySetup.study.telemetry; + } + + /** + * Sends an 'enter' telemetry ping for the study; should be called on addon + * startup for the reason ADDON_INSTALL. For more on study states like 'enter' + * see ABOUT.md at github.com/mozilla/shield-studies-addon-template + * @returns {void} + */ + firstSeen() { + log.debug(`firstSeen`); + this.throwIfNotSetup("firstSeen uses telemetry."); + this._telemetry({ study_state: "enter" }, "shield-study"); + } + + /** + * Marks the study's telemetry pings as being part of this experimental + * cohort in a way that downstream data pipeline tools + * (like ExperimentsViewer) can use it. + * @returns {void} + */ + setActive() { + this.throwIfNotSetup("setActive uses telemetry."); + const info = this.info(); + log.debug( + "marking TelemetryEnvironment", + info.studyName, + info.variation.name, + ); + TelemetryEnvironment.setExperimentActive( + info.studyName, + info.variation.name, + ); + } + + /** + * Removes the study from the active list of telemetry experiments + * @returns {void} + */ + unsetActive() { + this.throwIfNotSetup("unsetActive uses telemetry."); + const info = this.info(); + log.debug( + "unmarking TelemetryEnvironment", + info.studyName, + info.variation.name, + ); + TelemetryEnvironment.setExperimentInactive(info.studyName); + } + + /** + * Uninstalls the shield study addon, given its addon id. + * @param {string} id - the addon id + * @returns {void} + */ + uninstall(id) { + if (!id) id = this.info().addon.id; + if (!id) { + this.throwIfNotSetup("uninstall needs addon.id as arg or from setup."); + } + log.debug(`about to uninstall ${id}`); + AddonManager.getAddonByID(id, addon => addon.uninstall()); + } + + /** + * @async + * Adds the study to the active list of telemetry experiments and sends the + * "installed" telemetry ping if applicable + * @param {string} reason - The reason the addon has started up + * @returns {void} + */ + async startup({ reason }) { + this.throwIfNotSetup("startup"); + log.debug(`startup ${reason}`); + this.setActive(); + if (reason === REASONS.ADDON_INSTALL) { + this._telemetry({ study_state: "installed" }, "shield-study"); + } + } + + /** + * @async + * Ends the study: + * - Removes the study from the active list of telemetry experiments + * - Opens a new tab at a specified URL, if present (e.g. for a survey) + * - Sends a telemetry ping about the nature of the ending + * (positive, neutral, negative) + * - Sends an exit telemetry ping + * @param {Object} param - A details object describing why the study is ending + * @param {string} param.reason - The reason the study is ending, see + * schema.studySetup.json + * @param {string} param.fullname - optional, the full name of the study + * state, see schema.studySetup.json + * @returns {void} + */ + async endStudy({ reason, fullname }) { + this.throwIfNotSetup("endStudy"); + if (this._isEnding) { + log.debug("endStudy, already ending!"); + return; + } + this._isEnding = true; + log.debug(`endStudy ${reason}`); + this.unsetActive(); + // TODO glind, think about reason vs fullname + // TODO glind, think about race conditions for endings, ensure only one exit + /* + * Check if the study ending shows the user a page in a new tab + * (ex: survey, explanation, etc.) + */ + const ending = this.studySetup.study.endings[reason]; + if (ending) { + // baseUrl: needs to be appended with query arguments before use, + // exactUrl: used as is + const { baseUrl, exactUrl } = ending; + if (exactUrl) { + this.openTab(exactUrl); + } else if (baseUrl) { + const qa = await this.endingQueryArgs(); + qa.reason = reason; + qa.fullreason = fullname; + const fullUrl = mergeQueryArgs(baseUrl, qa); + log.debug(baseUrl, fullUrl); + this.openTab(fullUrl); + } + } + switch (reason) { + case "ineligible": + case "expired": + case "user-disable": + case "ended-positive": + case "ended-neutral": + case "ended-negative": + this._telemetry({ study_state: reason, fullname }, "shield-study"); + break; + default: + this._telemetry( + { + study_state: "ended-neutral", + study_state_fullname: reason, + }, + "shield-study", + ); + // unless we know better TODO grl + } + // these are all exits + this._telemetry({ study_state: "exit" }, "shield-study"); + this.uninstall(); // TODO glind. should be controllable by arg? + } + + /** + * @async + * Builds an object whose properties are query arguments that can be + * appended to a study ending url + * @returns {Object} - the query arguments for the study + */ + async endingQueryArgs() { + // TODO glind, make this back breaking! + this.throwIfNotSetup("endingQueryArgs"); + const info = this.info(); + const who = await this.getTelemetryId(); + const queryArgs = { + shield: PACKET_VERSION, + study: info.studyName, + variation: info.variation.name, + updateChannel: Services.appinfo.defaultUpdateChannel, + fxVersion: Services.appinfo.version, + addon: info.addon.version, // addon version + who, // telemetry clientId + }; + queryArgs.testing = Number(!this.telemetryConfig.removeTestingFlag); + return queryArgs; + } + + /** + * @async + * Validates and submits telemetry pings from StudyUtils. + * @param {Object} data - the data to send as part of the telemetry packet + * @param {string} bucket - the type of telemetry packet to be sent + * @returns {Promise|boolean} - A promise that resolves with the ping id + * once the ping is stored or sent, or false if + * - there is a validation error, + * - the packet is of type "shield-study-error" + * - the study's telemetryConfig.send is set to false + */ + async _telemetry(data, bucket = "shield-study-addon") { + log.debug(`telemetry in: ${bucket} ${JSON.stringify(data)}`); + this.throwIfNotSetup("_telemetry"); + const info = this.info(); + const payload = { + version: PACKET_VERSION, + study_name: info.studyName, + branch: info.variation.name, + addon_version: info.addon.version, + shield_version: UTILS_VERSION, + type: bucket, + data, + testing: !this.telemetryConfig.removeTestingFlag, + }; + + let validation; + /* istanbul ignore next */ + try { + validation = jsonschema.validate(payload, schemas[bucket]); + } catch (err) { + // Catch failures of unknown origin (could be library, addon, system...) + // if validation broke, GIVE UP. + log.error(err); + return false; + } + /* + * Handle validation errors by sending a "shield-study-error" + * telemetry ping with the error report. + * If the invalid payload is itself of type "shield-study-error", + * throw an error (to avoid a possible infinite loop). + */ + if (validation.errors.length) { + const errorReport = { + error_id: "jsonschema-validation", + error_source: "addon", + severity: "fatal", + message: JSON.stringify(validation.errors), + }; + if (bucket === "shield-study-error") { + // log: if it's a warn or error, it breaks jpm test + log.warn("cannot validate shield-study-error", data, bucket); + return false; // just die, maybe should have a super escape hatch? + } + return this.telemetryError(errorReport); + } + // emit(TelemetryWatcher, 'telemetry', [bucket, payload]); + log.debug(`telemetry: ${JSON.stringify(payload)}`); + // FIXME marcrowo: addClientId makes the ping not appear in test? + // seems like a problem with Telemetry, not the shield-study-utils library + const telOptions = { addClientId: true, addEnvironment: true }; + if (!this.telemetryConfig.send) { + log.debug("NOT sending. `telemetryConfig.send` is false"); + return false; + } + return TelemetryController.submitExternalPing(bucket, payload, telOptions); + } + + /** + * @async + * Validates and submits telemetry pings from the addon; mostly from + * webExtension messages. + * @param {Object} data - the data to send as part of the telemetry packet + * @returns {Promise|boolean} - see StudyUtils._telemetry + */ + async telemetry(data) { + log.debug(`telemetry ${JSON.stringify(data)}`); + const toSubmit = { + attributes: data, + }; + // lets check early, and respond with something useful? + return this._telemetry(toSubmit, "shield-study-addon"); + } + + /** + * Submits error report telemetry pings. + * @param {Object} errorReport - the error report, see StudyUtils._telemetry + * @returns {Promise|boolean} - see StudyUtils._telemetry + */ + telemetryError(errorReport) { + return this._telemetry(errorReport, "shield-study-error"); + } + + /** + * Sets the logging level. This is can be called from the addon, even + * after the log has been created. + * @param {string} descriptor - the Log level (e.g. "trace", "error", ...) + * @returns {void} + */ + setLoggingLevel(descriptor) { + log.level = Log.Level[descriptor]; + } +} + +/** + * Creates a log for debugging. + * Note: Log.jsm is used over Console.log/warn/error because: + * - Console has limited log levels + * - Console is not pref-controllable. Log can be turned on and off using + * studySetup.log (see ./addon/Config.jsm in + * github.com/mozilla/shield-study-addon-template) + * - Console can create linting errors and warnings. + * @param {string} name - the name of the Logger instance + * @param {string} levelWord - the Log level (e.g. "trace", "error", ...) + * @returns {Object} - the Logger instance, see gre/modules/Log.jsm + */ +function createLog(name, levelWord) { + Cu.import("resource://gre/modules/Log.jsm"); + const L = Log.repository.getLogger(name); + L.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter())); + // should be a config / pref + L.level = Log.Level[levelWord] || Log.Level.Debug; + L.debug("log made", name, levelWord, Log.Level[levelWord]); + return L; +} + +// addon state change reasons +const REASONS = { + APP_STARTUP: 1, // The application is starting up. + APP_SHUTDOWN: 2, // The application is shutting down. + ADDON_ENABLE: 3, // The add-on is being enabled. + ADDON_DISABLE: 4, // The add-on is being disabled. (Also sent at uninstall) + ADDON_INSTALL: 5, // The add-on is being installed. + ADDON_UNINSTALL: 6, // The add-on is being uninstalled. + ADDON_UPGRADE: 7, // The add-on is being upgraded. + ADDON_DOWNGRADE: 8, // The add-on is being downgraded. +}; +for (const r in REASONS) { + REASONS[REASONS[r]] = r; +} + +// Actually create the singleton. +const studyUtils = new StudyUtils(); + +// to make this work with webpack! +this.EXPORTED_SYMBOLS = EXPORTED_SYMBOLS; +this.studyUtils = studyUtils; diff --git a/webExtensionApis/study/src/studyUtilsBootstrap.js b/webExtensionApis/study/src/studyUtilsBootstrap.js new file mode 100644 index 0000000..ff419f6 --- /dev/null +++ b/webExtensionApis/study/src/studyUtilsBootstrap.js @@ -0,0 +1,146 @@ +"use strict"; + +const EXPORTED_SYMBOLS = ["Bootstrap"]; + +const { utils: Cu } = Components; +Cu.import("resource://gre/modules/Services.jsm"); + +this.Bootstrap = function(studySetup, studyUtils) { + return { + /** + * Use console as our logger until there is a log() method in studyUtils that we can rely on + */ + log: console, + + /** + * + * @param manifest + * @param reason + * @returns {Promise} + */ + async configure(extension) { + const { manifest } = extension; + + const addonId = manifest.applications.gecko.id; + const addonVersion = manifest.version; + this.initStudyUtils(addonId, addonVersion); + + // choose and set variation + await this.selectVariation(); + }, + + async startup(extension) { + const { startupReason } = extension; + + this.log.debug("startup", startupReason); + + // Check if the user is eligible to run this study using the |isEligible| + // function when the study is initialized + if ( + startupReason === "ADDON_INSTALL" || + startupReason === "ADDON_UPGRADE" + ) { + // telemetry "enter" ONCE + studyUtils.firstSeen(); + if (!studySetup.eligible) { + this.log.debug("User is ineligible, ending study."); + // 1. uses studySetup.endings.ineligible.url if any, + // 2. sends UT for "ineligible" + // 3. then uninstalls addon + await studyUtils.endStudy({ reason: "ineligible" }); + return; + } + } + + if (studySetup.expired) { + await studyUtils.endStudy({ reason: "expired" }); + return; + } + + /* + * Adds the study to the active list of telemetry experiments, + * and sends the "installed" telemetry ping if applicable + */ + await studyUtils.startup({ startupReason }); + + // log what the study variation and other info is. + this.log.debug(`info ${JSON.stringify(studyUtils.info())}`); + }, + + initStudyUtils(id, version) { + // validate study config + studySetup.addon = { id, version }; + studyUtils.setup(studySetup); + // TODO bdanforth: patch studyUtils to setLoggingLevel as part of setup method + //studyUtils.setLoggingLevel(...); + }, + + // choose the variation for this particular user, then set it. + async selectVariation() { + const variation = + this.getVariationFromPref(studySetup.weightedVariations) || + (await studyUtils.deterministicVariation( + studySetup.weightedVariations, + )); + studyUtils.setVariation(variation); + this.log.debug(`studyUtils has studySetup and variation.name: ${ + variation.name + }. + Ready to send telemetry`); + return variation; + }, + + // helper to let Dev or QA set the variation name + getVariationFromPref(weightedVariations) { + const name = Services.prefs.getCharPref( + studySetup.variationOverridePreference, + "", + ); + if (name !== "") { + const variation = weightedVariations.filter(x => x.name === name)[0]; + if (!variation) { + throw new Error(`about:config => ${ + studySetup.variationOverridePreference + } set to ${name}, + but no variation with that name exists.`); + } + return variation; + } + return name; + }, + + /** + * Shutdown needs to distinguish between USER-DISABLE and other + * times that `endStudy` is called. + * + * studyUtils._isEnding means this is a '2nd shutdown'. + */ + async shutdown(addonData, reason) { + this.log.debug("shutdown", studyUtils.REASONS[reason] || reason); + + const isUninstall = + reason === studyUtils.REASONS.ADDON_UNINSTALL || + reason === studyUtils.REASONS.ADDON_DISABLE; + if (isUninstall) { + this.log.debug("uninstall or disable"); + } + + if (isUninstall && !studyUtils._isEnding) { + // we are the first 'uninstall' requestor => must be user action. + this.log.debug("probably: user requested shutdown"); + studyUtils.endStudy({ reason: "user-disable" }); + } + + // normal shutdown, or 2nd uninstall request + }, + + uninstall(addonData, reason) { + this.log.debug("uninstall", reason); + }, + + install(addonData, reason) { + this.log.debug("install", reason); + // handle ADDON_UPGRADE (if needful) here + }, + }; +}; diff --git a/webExtensionApis/study/webpack.config.js b/webExtensionApis/study/webpack.config.js new file mode 100644 index 0000000..5c6ea0e --- /dev/null +++ b/webExtensionApis/study/webpack.config.js @@ -0,0 +1,11 @@ +/* eslint-env node */ +const path = require("path"); + +module.exports = { + entry: "./src/index.js", + output: { + path: path.resolve(__dirname), + filename: "api.js", + libraryTarget: "this", // Possible value - amd, commonjs, commonjs2, commonjs-module, this, var + }, +}; diff --git a/webpack.config.js b/webpack.config.js deleted file mode 100644 index c888164..0000000 --- a/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -var path = require('path'); -const webpack = require('webpack'); //to access built-in plugins - -module.exports = { - entry: './src/StudyUtils.in.jsm', - output: { - path: path.resolve(__dirname, 'dist'), - filename: 'StudyUtils.jsm', - libraryTarget: 'this' // Possible value - amd, commonjs, commonjs2, commonjs-module, this, var - } -};