diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..fc1adf3 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,2 @@ +test/reports/* +dist diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..07ba798 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,87 @@ +{ + "extends": "eslint:recommended", + "env": { + "browser": true, + "es6": true, + "node": true, + "jest": true + }, + "parserOptions": { + "ecmaVersion": 6 + }, + "rules": { + // Possible errors + "no-console": "error", + "no-extra-parens": "error", + "no-loss-of-precision": "error", + "no-promise-executor-return": "error", + "no-template-curly-in-string": "error", + "no-unreachable-loop": "error", + "require-atomic-updates": "error", + "no-useless-backreference": "error", + // Best practices + "array-callback-return": ["error", { "checkForEach": true }], + "block-scoped-var": "error", + "consistent-return": "error", + "curly": "error", + "default-case": "error", + "default-case-last": "error", + "default-param-last": "error", + "dot-notation": "error", + "eqeqeq": "error", + "no-constructor-return": "error", + "no-else-return": "error", + "no-extra-bind": "error", + "no-multi-spaces" : "error", + "no-underscore-dangle": "error", + "no-sequences": "error", + "no-unused-expressions": "warn", + "prefer-regex-literals": "warn", + "valid-jsdoc": ["error", {"requireReturn": false}], + // Strict mode + "strict": "error", + // Variables + "no-shadow": "error", + "no-undefined": "error", + "no-use-before-define": "error", + // Stylistic issues + "array-bracket-newline": ["error", "consistent"], + "array-bracket-spacing": ["error", "never"], + "array-element-newline": ["error", "consistent"], + "block-spacing": "error", + "brace-style": "error", + "camelcase": ["error", {"ignoreDestructuring": true, "ignoreGlobals": true}], + "comma-dangle": ["error", "only-multiline"], + "computed-property-spacing": ["error", "never", { "enforceForClassMembers": true }], + "consistent-this": ["error", "self"], + "eol-last": ["error", "always"], + "func-call-spacing": ["error", "never"], + "func-style": ["error", "declaration", { "allowArrowFunctions": true }], + "indent": ["error", 4], + "keyword-spacing": "error", + "linebreak-style": ["error", "unix"], + "max-len": ["error", 120, {"ignoreComments": true}], + "multiline-comment-style": ["error", "starred-block"], + "new-cap": ["error", { "properties": false }], + "new-parens": "error", + "newline-per-chained-call": "error", + "no-multi-assign": "error", + "no-multiple-empty-lines": ["error", { "max": 1 } ], + "no-trailing-spaces": "error", + "object-curly-spacing": ["error", "never"], + "padded-blocks": ["error", "never"], + "quotes": ["error", "single"], + "semi": ["error", "always"], + "semi-style": ["error", "last"], + "space-before-function-paren": ["error", "never"], + "space-in-parens": ["error", "never"], + "spaced-comment": ["error", "always"], + // ECMAScript 6 + "arrow-parens": ["error", "always"], + "arrow-spacing": "error", + "no-confusing-arrow": "error", + "no-var": "error", + "prefer-const": "error", + "prefer-spread": "error" + } +} diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..fcff4a4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,26 @@ +## Prerequisites + +- [ ] I've read & comply with the [contributing guidelines](https://github.com/Genymobile/genymotion-device-web-player/blob/main/CONTRIBUTING.md) +* [ ] I've searched open issues if my demand is already reported. + +## Description + +Description of the bug or feature / support request . + +## Steps to Reproduce + +1. [First Step] +2. [Second Step] +3. [and so on...] + +**Expected behavior:** + +What you expected to happen. + +**Actual behavior:** + +What actually happened. + +## Versions / environment + +If you are reporting a bug, please describe your environement and the versions you are using (you can get this information from executing `npm version`). diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..f5e7bfb --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,18 @@ +## Description + +Please include a summary of the change and which issue is fixed if any. Please also include relevant motivation and context (a screenshot is appreciated). + +Fixes # + +## Type of change + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) + +## Checklist: + +- [ ] I've read & comply with the [contributing guidelines](https://github.com/Genymobile/genymotion-device-web-player/blob/main/CONTRIBUTING.md) +- [ ] I have tested my code for new features & regressions on both mobile & desktop devices, using the latest version of major browsers. +- [ ] I have made corresponding changes to the documentation (README.md). +- [ ] I've checked my modifications for any breaking changes. diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml new file mode 100644 index 0000000..fb9767a --- /dev/null +++ b/.github/workflows/integration.yml @@ -0,0 +1,32 @@ +# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node +# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions + +name: Integration + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [12.x] + # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + cache: 'yarn' + - run: yarn install + - run: yarn validate + - run: yarn test + diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..ac30a98 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,38 @@ +# This workflow will run lints & tests then create a GitHub release and publish a package to NPM +# For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages + +name: Release + +on: + push: + tags: [v*] + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: 12 + registry-url: https://registry.npmjs.org/ + - name: Build project + run: | + yarn install + yarn validate + yarn test + yarn build + - name: Create GitHub Release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: Release ${{ github.ref }} + draft: false + prerelease: false + + - name: NPM Release + run: yarn publish --access public + env: + NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9e963e8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,148 @@ + +# Created by https://www.gitignore.io/api/node,jetbrains,linux,osx,virtualenv + +# Build artifact +/dist + +### Node ### +# Logs +logs +*.log +npm-debug.log* + +# Runtime data +pids +*.pid +*.seed + +# Documentation +docs/private +docs/public + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# test report directory +tests/reports + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules +jspm_packages + +# Optional npm cache directory +.npm + +# Optional REPL history +.node_repl_history + +### Microsoft ### +# Visual Studio Code +.vscode/ + +### JetBrains ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm +.idea/* +*.iml + +## File-based project format: +*.iws + +## Plugin-specific files: + +# IntelliJ +/out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +### JetBrains Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml + + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + + +### OSX ### +*.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + + +### VirtualEnv ### +# Virtualenv +# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ +.Python +[Bb]in +[Ii]nclude +[Ll]ib +[Ll]ib64 +[Ll]ocal +[Ss]cripts +pyvenv.cfg +.venv +pip-selfcheck.json + + +### Other ### +# Swap files +*.swp diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..81e1663 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,132 @@ + +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement [here](https://www.genymotion.com/contact/). +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0bc11ba --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Genymobile + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..028225e --- /dev/null +++ b/README.md @@ -0,0 +1,395 @@ +# Genymotion device web player + +![npm](https://img.shields.io/npm/v/@genymotion/device-web-player) +![GitHub](https://img.shields.io/github/license/Genymobile/genymotion-device-web-player) + + + +This repository contains the Genymotion device web player javascript SDK. +It provides an easy way to integrate **Genymotion devices** running in the cloud into any web application. You will be able to display an emulator screen and interact with the device. + +It focuses on: + + - **compatibility** (vanilla javascript, no external framework used) + - **performance** (30fps or more) + - **quality** (Up to 1920×1080) + - **low latency** + +For more information about Genymotion devices, please visit [genymotion website](https://www.genymotion.com). + +## Table of contents +1. [Requirements](#Requirements) +2. [Getting started](#getting-started) + 1. [With NPM/Yarn](#with-npmyarn) + 2. [With CDN](#with-cdn) +3. [Usage](#usage) +4. [Features & options](#features--options) + +## Requirements +A Modern, WebRTC compatible, Web browser: + - Chrome (60+) + - Firefox (58+) + - Safari (11+) + - Edge (15+) + - Opera (22+) + +## Getting started +### With NPM/Yarn + +Using yarn: +```bash +yarn add @genymotion/device-web-player +``` + +Using npm: +```bash +npm install @genymotion/device-web-player +``` + +Package import (commonJS): +```js +const GenymotionManager = require('genymotion/device-web-player'); +``` + +```html + +``` + +### With CDN + +```html + + +``` + +## Usage + +Use `GenymotionManager` to instanciate one or more Genymotion device player. +All you need is an HTML element to use as a container. See example below. + +```html +
+ + +``` + +## Features & options + +A device player instance can be configured using the `options` argument (object). Possible configuration key / value are described below. + +### `template` + +* **Type:** `String` +* **Default:** `player` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** +Defines the layout of the player. Can be one of the following: `bootstrap`, `fullscreen`, `fullwindow`, `player`, `player_minimal`, `player_no_toolbar`, `player_partial`. + +### `token` + +* **Type:** `String` +* **Default:** `undefined` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** +Instance access token, the shared secret used to connect to the device. + +### `i18n` + +* **Type:** `Object` +* **Default:** `{}` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** +Alternative translation for the player UI. + +### `stun` + +* **Type:** `Object` +* **Default:** `{}` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** +WebRTC STUN servers configuration. Format: + +```js +{ + urls: [ + 'stun:stun-server1.org:80', + 'stun:stun-server2.org:443', + ... + ], +} +``` + +### `turn` + +* **Type:** `Object` +* **Default:** `{}` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** +WebRTC TURN servers configuration. Format: +```js +{ + urls: [], + username: "myUsername", + credential: "myPassword", + default: false // Whether or not we should use the TURN servers by default. Default: false. +} +``` + +### `streamResolution` + +... + +* **Type:** `Boolean` +* **Default:** `true` +* **Compatibility:** `SaaS` +* **Details:** +Enables or disables the video stream quality widget. + +### `streamBitrate` + +* **Type:** `Boolean` +* **Default:** `false` +* **Compatibility:** `SaaS` +* **Details:** +Enables or disables the stream bitrate widget. + +### `touch` + +* **Type:** `Boolean` +* **Default:** `true` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** +Enables or disables the touch events (fingers on screen). If you want to disable all VM interaction, please also disable `mouse` and `keyboard`. + +### `mouse` + +* **Type:** `Boolean` +* **Default:** `true` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** +Enables or disables the mouse events. If you want to disable all VM interaction, please also disable `touch` and `keyboard`. + +### `keyboard` + +* **Type:** `Boolean` +* **Default:** `true` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** +Enables or disables the keyboard widget. This widget can be used to transmit keyboard key strokes to the Android virtual device. + +### `volume` + +... + +* **Type:** `Boolean` +* **Default:** `true` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** +Enables or disables the volume widget. This widget can be used to increase or decrease the volume of the Android virtual device. + +### `rotation` + +... + +* **Type:** `Boolean` +* **Default:** `true` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** +Enables or disables the rotation widget. This widget can be used to rotate the Android virtual device. + +### `navbar` + +... +... +... + +* **Type:** `Boolean` +* **Default:** `true` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** +Enables or disables the navbar widgets. This widget can be used to navigate in the Android virtual device like when using hardware buttons. + +### `power` + +... + +* **Type:** `Boolean` +* **Default:** `true` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** +Enables or disables the power widget. This widget can be used to poweroff or reboot the Android virtual device. + +### `fullscreen` + +... +... + +* **Type:** `Boolean` +* **Default:** `true` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** +Enables or disables the fullscreen widget. This widget can be used to make the player go fullscreen. + +### `camera` + +... + +* **Type:** `Boolean` +* **Default:** `true` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** +Enables or disables the camera widget. This widget can be used to forward local webcam to the Android virtual device. + +### `fileUpload` + +... + +* **Type:** `Boolean` +* **Default:** `true` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** +Enables or disables the fileUpload widget and drag & drop. This widget can be used to forward local file to the Android virtual device. When drag & dropping APK or ZIP files, it will install them. + +### `fileUploadUrl` + +* **Type:** `String` +* **Default:** `undefined` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** +Set the file upload url, required if `fileUpload` is set to `true`. + +### `clipboard` + +... + +* **Type:** `Boolean` +* **Default:** `true` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** +Enables or disables the clipboard widget. This widget can be used to forward local clipboard to the Android virtual device. + +### `battery` + +... + +* **Type:** `Boolean` +* **Default:** `true` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** +Enables or disables the battery widget. This widget can be used to set the battery level and state of the Android virtual device. + +### `gps` + +... + +* **Type:** `Boolean` +* **Default:** `true` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** +Enables or disables the gps widget. This widget can be used to set the gps location of the Android virtual device. + +### `gpsSpeedSupport` + +* **Type:** `Boolean` +* **Default:** `false` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** +Enables or disables gps speed support. + +### `capture` + +... + +* **Type:** `Boolean` +* **Default:** `true` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** +Enables or disables the capture widget. This widget can be used to capture the screen of the Android virtual device (screenshot or screencast). + +### `identifiers` + +... + +* **Type:** `Boolean` +* **Default:** `true` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** + +Enables or disables the identifiers widget. This widget can be used to set the identifiers (Android ID / IMEI) of the Android virtual device. + +### `network` + +... + +* **Type:** `Boolean` +* **Default:** `true` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** +Enables or disables the network widget. This widget can be used to set the network (throttling and baseband) of the Android virtual device. + +### `phone` + +... + +* **Type:** `Boolean` +* **Default:** `true` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** + +Enables or disables the phone widget. This widget can be used to send SMS or phone call the Android virtual device. + +### `diskIO` + +... + +* **Type:** `Boolean` +* **Default:** `true` +* **Compatibility:** `PaaS`, `SaaS` +* **Details:** +Enables or disables the diskIO widget. This widget can be used to modify Disk IO (throttling) of the Android virtual device. + + +### `translateHomeKey` + +* **Type:** `Boolean` +* **Default:** `false` +* **Compatibility:** `PaaS` +* **Details:** +Translate home key to `META` + `ENTER` + + +### `baseband` + +... + +* **Type:** `Boolean` +* **Default:** `false` +* **Compatibility:** `PaaS` +* **Details:** +Enable or disable baseband (MMC/MNC) widget + +### `connectionFailedURL` + +* **Type:** `String` +* **Default:** `undefined` +* **Compatibility:** `SaaS`, `PaaS` +* **Details:** +Redirection page in case of connection error. diff --git a/bower.json b/bower.json new file mode 100644 index 0000000..cfea484 --- /dev/null +++ b/bower.json @@ -0,0 +1,9 @@ +{ + "name": "genymotion-webrtc-client", + "main": [ + "dist/js/gm-player.min.js", + "dist/css/gm-player.css" + ], + "moduleType": "globals", + "version": "1.4.1" +} diff --git a/doc/assets/ic-battery_active_black.svg b/doc/assets/ic-battery_active_black.svg new file mode 100644 index 0000000..117093d --- /dev/null +++ b/doc/assets/ic-battery_active_black.svg @@ -0,0 +1,12 @@ + + + + ic-battery_active_black + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/doc/assets/ic-nav_android_back_active_black.svg b/doc/assets/ic-nav_android_back_active_black.svg new file mode 100644 index 0000000..8181559 --- /dev/null +++ b/doc/assets/ic-nav_android_back_active_black.svg @@ -0,0 +1,12 @@ + + + + ic-nav_android_active_black + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/doc/assets/ic-nav_android_home_active_black.svg b/doc/assets/ic-nav_android_home_active_black.svg new file mode 100644 index 0000000..da1ff67 --- /dev/null +++ b/doc/assets/ic-nav_android_home_active_black.svg @@ -0,0 +1,12 @@ + + + + ic-nav_android_home_active_black + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/doc/assets/ic-nav_android_multiapp_active_black.svg b/doc/assets/ic-nav_android_multiapp_active_black.svg new file mode 100644 index 0000000..dec8656 --- /dev/null +++ b/doc/assets/ic-nav_android_multiapp_active_black.svg @@ -0,0 +1,12 @@ + + + + ic-nav_android_multiapp_active_black + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/doc/assets/ic-resolution_active_black.svg b/doc/assets/ic-resolution_active_black.svg new file mode 100644 index 0000000..fe85a92 --- /dev/null +++ b/doc/assets/ic-resolution_active_black.svg @@ -0,0 +1,12 @@ + + + + ic-resolution_active_black + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/doc/assets/ic-screencast_disabled.svg b/doc/assets/ic-screencast_disabled.svg new file mode 100644 index 0000000..bda60ca --- /dev/null +++ b/doc/assets/ic-screencast_disabled.svg @@ -0,0 +1,7 @@ + + + + + diff --git a/doc/assets/ic-screenshot_active_black.svg b/doc/assets/ic-screenshot_active_black.svg new file mode 100644 index 0000000..316af4d --- /dev/null +++ b/doc/assets/ic-screenshot_active_black.svg @@ -0,0 +1,22 @@ + + + + ic-screenshot_active_black + Created with Sketch. + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/assets/ic-screenshot_disabled.svg b/doc/assets/ic-screenshot_disabled.svg new file mode 100644 index 0000000..e970f66 --- /dev/null +++ b/doc/assets/ic-screenshot_disabled.svg @@ -0,0 +1,9 @@ + + + + + diff --git a/doc/assets/ic_baseband_active_black.svg b/doc/assets/ic_baseband_active_black.svg new file mode 100644 index 0000000..c2ead57 --- /dev/null +++ b/doc/assets/ic_baseband_active_black.svg @@ -0,0 +1,12 @@ + + + + ic_baseband_active_black + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/doc/assets/ic_camera_active_black.svg b/doc/assets/ic_camera_active_black.svg new file mode 100644 index 0000000..3cea125 --- /dev/null +++ b/doc/assets/ic_camera_active_black.svg @@ -0,0 +1,15 @@ + + + + ic_camera_active_black + Created with Sketch. + + + + + + + + + + diff --git a/doc/assets/ic_clipboard_active_black.svg b/doc/assets/ic_clipboard_active_black.svg new file mode 100644 index 0000000..a0c5602 --- /dev/null +++ b/doc/assets/ic_clipboard_active_black.svg @@ -0,0 +1,3 @@ + + + diff --git a/doc/assets/ic_cloud_upload_active_black.svg b/doc/assets/ic_cloud_upload_active_black.svg new file mode 100644 index 0000000..acb296f --- /dev/null +++ b/doc/assets/ic_cloud_upload_active_black.svg @@ -0,0 +1,12 @@ + + + + +Group 5 +Created with Sketch. + + diff --git a/doc/assets/ic_diskIO_active_black.svg b/doc/assets/ic_diskIO_active_black.svg new file mode 100644 index 0000000..c2dd0bd --- /dev/null +++ b/doc/assets/ic_diskIO_active_black.svg @@ -0,0 +1,34 @@ + + + + ic_diskIO_active_black + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/assets/ic_fullscreen_active_black.svg b/doc/assets/ic_fullscreen_active_black.svg new file mode 100644 index 0000000..0f143fc --- /dev/null +++ b/doc/assets/ic_fullscreen_active_black.svg @@ -0,0 +1,39 @@ + + + + ic_fullscreen_active_black + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/assets/ic_fullscreen_exit_active_black.svg b/doc/assets/ic_fullscreen_exit_active_black.svg new file mode 100644 index 0000000..3d6368f --- /dev/null +++ b/doc/assets/ic_fullscreen_exit_active_black.svg @@ -0,0 +1,39 @@ + + + + ic_fullscreen_exit_active_black + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/assets/ic_icon_power_inactive_black.svg b/doc/assets/ic_icon_power_inactive_black.svg new file mode 100644 index 0000000..bab7ae5 --- /dev/null +++ b/doc/assets/ic_icon_power_inactive_black.svg @@ -0,0 +1,12 @@ + + + + ic_icon_power_inactive_black + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/doc/assets/ic_id_active_black.svg b/doc/assets/ic_id_active_black.svg new file mode 100644 index 0000000..6bd534a --- /dev/null +++ b/doc/assets/ic_id_active_black.svg @@ -0,0 +1,23 @@ + + + + ic_id_active_black + Created with Sketch. + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/assets/ic_location_active_black.svg b/doc/assets/ic_location_active_black.svg new file mode 100644 index 0000000..dcb3fd8 --- /dev/null +++ b/doc/assets/ic_location_active_black.svg @@ -0,0 +1,12 @@ + + + + ic_location_active_black + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/doc/assets/ic_network_active_black.svg b/doc/assets/ic_network_active_black.svg new file mode 100644 index 0000000..e44af97 --- /dev/null +++ b/doc/assets/ic_network_active_black.svg @@ -0,0 +1,12 @@ + + + + ic_network_active_black + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/doc/assets/ic_rotation_active_black.svg b/doc/assets/ic_rotation_active_black.svg new file mode 100644 index 0000000..f82037b --- /dev/null +++ b/doc/assets/ic_rotation_active_black.svg @@ -0,0 +1,14 @@ + + + + ic_rotation_active_black + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/doc/assets/ic_sound_active_black.svg b/doc/assets/ic_sound_active_black.svg new file mode 100644 index 0000000..eb53593 --- /dev/null +++ b/doc/assets/ic_sound_active_black.svg @@ -0,0 +1,14 @@ + + + + ic_sound_active_black + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/doc/assets/ic_textandcall_active_black.svg b/doc/assets/ic_textandcall_active_black.svg new file mode 100644 index 0000000..cac61b4 --- /dev/null +++ b/doc/assets/ic_textandcall_active_black.svg @@ -0,0 +1,15 @@ + + + + ic_textandcall_active_black + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/doc/assets/screenshot.png b/doc/assets/screenshot.png new file mode 100644 index 0000000..9542570 Binary files /dev/null and b/doc/assets/screenshot.png differ diff --git a/gulp/graspify-squery.js b/gulp/graspify-squery.js new file mode 100644 index 0000000..4f4087a --- /dev/null +++ b/gulp/graspify-squery.js @@ -0,0 +1,46 @@ +'use strict'; + +const grasp = require('grasp'); +const transformTools = require('browserify-transform-tools'); + +const options = { + jsFilesOnly: true, +}; + +/** + * String transform is called per-module. + * In that, as many `require` calls you have, that many times it is called. + * If you replace `require` call, transform for that module won't be called. + * + * Transform can be called globally as `browserify -g graspify`. + * In that case transform is called for each nested module as well, + * getting global config, defined in package.json. + * + * `opts.config` is taken from package.json, can be whether object or array. + * `opts.opts` is taken as browserify transform param. + * + * Module taken from https://www.npmjs.com/package/graspify + */ +module.exports = transformTools.makeStringTransform('graspify', options, (content, opts, done) => { + try { + // Normalize plain replacements + if (opts.opts && typeof opts.opts[0] === 'string') { + opts.opts = [opts.opts]; + } + if (opts.config && typeof opts.config[0] === 'string') { + opts.config = [opts.config]; + } + + // Merge opts & config for the full list of replacements an loop over + [].concat(opts.opts || [], opts.config || []).forEach((args) => { + const selectorType = args.length === 3 ? args.shift() : 'squery'; + const selector = args[0]; + const replacement = args[1]; + content = grasp.replace(selectorType, selector, replacement, content); + }); + + done(null, content); + } catch (e) { + done(e); + } +}); diff --git a/gulp/gulp-template-collector.js b/gulp/gulp-template-collector.js new file mode 100644 index 0000000..4e7d8f0 --- /dev/null +++ b/gulp/gulp-template-collector.js @@ -0,0 +1,53 @@ +'use strict'; + +/** + * gulp/gulp-template-collector.js + * Gulp plugin to collect all template resources + */ + +const through = require('through2'); +const File = require('vinyl'); + +/** + * templateCollector + * Collect / combine all resources for an individual template + * + * @param {Object} options {Object} + * @param {string} options.file concat all templates into single file + * @return {Object} Gulp plugin + */ +module.exports = function templateCollector(options) { + const templates = {}; + options = options || {}; + options.file = options.file || 'templates.js'; + + return through.obj( + function transform(file, enc, done) { + // Ensure file, not directory + if (file.isNull()) { + return done(); + } + + // Break up filename + const pieces = file.relative.split('/'); + const template = pieces[0]; + const fileName = pieces[1]; + + // Capture contents + if (!templates[template]) { + templates[template] = {}; + } + templates[template][fileName.split('.')[1]] = file.contents.toString(); + + return done(); + }, + function flush(done) { + const templateBlob = JSON.stringify(templates); + this.push(new File({ + path: options.file, + contents: Buffer.from(templateBlob), + })); + done(); + } + ); +}; diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..86dfe5b --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,212 @@ +'use strict'; + +/** + * gulpfile.js + * Gulp task definitions + */ + +// This variable is used to store templates generated from the template folder +let templates; + +const autoprefixer = require('gulp-autoprefixer'); +const babel = require('gulp-babel'); +const base64 = require('gulp-css-base64'); +const browserify = require('browserify'); +const browserSync = require('browser-sync').create(); +const concat = require('gulp-concat'); +const del = require('del'); +const graspify = require('./gulp/graspify-squery'); +const gulp = require('gulp'); +const gulpif = require('gulp-if'); +const inject = require('gulp-inject'); +const merge2 = require('merge2'); +const minifyCss = require('gulp-clean-css'); +const minifyHtml = require('gulp-htmlmin'); +const sass = require('gulp-sass'); +const source = require('vinyl-source-stream'); +const streamify = require('gulp-streamify'); +const tap = require('gulp-tap'); +const templateCollector = require('./gulp/gulp-template-collector'); +const uglify = require('gulp-uglify-es').default; +const using = require('gulp-using'); +const util = require('gulp-util'); + +const PATHS = { + SRC: { + APP: 'GenymotionManager.js', + BASE: './src', + WORKER: './src/worker', + TEMPLATES: './src/templates', + ASSETS: { + STYLES: './src/scss' + } + }, + DEST: { + BASE: 'dist', + TEMPLATES: 'dist/templates', + ASSETS: { + CSS: 'dist/css' + }, + LIB: { + JS: 'dist/js', + CSS: 'dist/css' + } + }, + TEST: { + UTIL: './test/util', + UT: './test/specs', + E2E: './test/e2e' + } + +}; + +function getTemplateStylesStream() { + return gulp.src([PATHS.SRC.TEMPLATES + '/**/*.css']) + .pipe(base64()); +} + +function getTemplatesStream() { + return merge2( + gulp.src([PATHS.SRC.TEMPLATES + '/**/*.html']), + gulp.src([PATHS.SRC.TEMPLATES + '/**/*.js']), + getTemplateStylesStream() + ).pipe(templateCollector()); +} + +// Clean dist dir +gulp.task('clean', function(cb) { + del([PATHS.DEST.BASE]).then(function() { + cb(); + }, function(err) { + cb(err); + }); +}); + +// HTML templates +gulp.task('app-partials', function() { + return gulp.src(['*.html']) + .pipe(gulpif(util.env.debug, using())) + .pipe(gulpif(util.env.production, minifyHtml({empty: true}))) + .pipe(gulp.dest(PATHS.DEST.BASE)); +}); + +// SASS styles +gulp.task('app-styles', function() { + return gulp.src(PATHS.SRC.ASSETS.STYLES + '/**/*.scss') + .pipe(gulpif(util.env.debug, using())) + .pipe(sass().on('error', sass.logError)) + .pipe(base64()) + .pipe(autoprefixer()) + .pipe(gulpif(util.env.production, minifyCss())) + .pipe(concat('gm-player.css')) + .pipe(gulp.dest(PATHS.DEST.ASSETS.CSS)); +}); + +gulp.task('app-templates', function() { + return getTemplatesStream() + .pipe(tap(function(file) { + // After getting the templates to a JSON form, we need to transform it to a javascript string + templates = file.contents.toString(); + templates = templates.replace(/\\n/g, ''); // we remove \n + templates = templates.replace(/\\"/g, 'xFic1RoIH8'); // we change \" to a tmp replacement string + templates = templates.replace(/'/g, '\\\''); // we change all ' to \' + templates = templates.replace(/"/g, '\''); // we replace all " by ' + templates = templates.replace(/xFic1RoIH8/g, '\\"'); // we change back the tmp replacement string to \" + })); +}); + +function getBundler() { + return browserify({ + entries: [PATHS.SRC.BASE + '/' + PATHS.SRC.APP], + standalone: 'GenymotionManager', + debug: true + }).transform(graspify, ['#GEN_TEMPLATES', templates]); +} + +gulp.task('app-js', function() { + return merge2(getBundler().bundle() + .pipe(source(PATHS.SRC.APP)), {end: true}) + .pipe(gulpif(util.env.debug, using())) + .pipe(gulpif(util.env.production, streamify(babel({ + compact: false, + presets: [ + [ + '@babel/env', { + targets: 'last 2 versions, not dead, not ie 11, not ie_mob 11, not op_mini all, not and_uc 12' + } + ] + ] + })))) + .pipe(streamify(concat('gm-player.min.js'))) + .pipe(gulpif(util.env.production, streamify(uglify()))) + .pipe(gulp.dest(PATHS.DEST.LIB.JS)); +}); + +// Dependencies injection +gulp.task('inject', function() { + return gulp.src('*.html') + .pipe(inject( + gulp.src([ + PATHS.DEST.LIB.CSS + '/**/*.css', + PATHS.DEST.LIB.JS + '/**/*.js' + ], {read: false}) + , { + addRootSlash: false, + ignorePath: PATHS.DEST.BASE + } + )) + .pipe(gulp.dest(PATHS.DEST.BASE)); +}); + +// Simple webserver +gulp.task('connect', function() { + browserSync.init({ + server: { + baseDir: PATHS.DEST.BASE + }, + port: 8000 + }); +}); + +// Build project +gulp.task('build', gulp.series( + 'clean', + 'app-templates', + gulp.parallel('app-partials', 'app-styles', 'app-js'), + 'inject', + function(cb) { + cb(); + } +)); + +// Watch project update +gulp.task('watch', gulp.series('build', function() { + gulp.watch([ + PATHS.SRC.ASSETS.STYLES + '/**/*.scss' + ], gulp.series('app-styles')); + + gulp.watch([ + PATHS.TEST.UT + '/**/*.js' + ], gulp.series('test')); + + gulp.watch([ + PATHS.SRC.BASE + '/*.js', + PATHS.SRC.BASE + '/**/*.js', + PATHS.SRC.WORKER + '/*.js', + PATHS.SRC.WORKER + '/**/*.js', + PATHS.SRC.TEMPLATES + '/**/*' + ], gulp.series('app-js')); +})); + +// Serve project +gulp.task('serve', gulp.series('watch', function(cb) { + browserSync.init({ + files: [PATHS.DEST.BASE + '/**/*'], + server: { + baseDir: PATHS.DEST.BASE + }, + port: 8000 + }); + + cb(); +})); diff --git a/package.json b/package.json new file mode 100644 index 0000000..8996efe --- /dev/null +++ b/package.json @@ -0,0 +1,73 @@ +{ + "name": "@genymotion/device-web-player", + "version": "1.4.1", + "description": "Genymotion Virtual Device Web Player", + "main": "dist/js/gm-player.min.js", + "engines": { + "node": ">=12" + }, + "scripts": { + "test": "jest --config tests/config.js", + "lint": "eslint src tests gulp", + "checkstyle": "eslint -f checkstyle -o ./tests/reports/lint/report.xml src tests gulp", + "validate": "yarn lint; yarn checkstyle", + "build": "gulp build --production" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Genymobile/genymotion-device-web-player.git" + }, + "author": "Genymotion team (https://www.genymotion.com)", + "license": "MIT", + "bugs": { + "url": "https://github.com/Genymobile/genymotion-device-web-player/issues" + }, + "homepage": "https://github.com/Genymobile/genymotion-device-web-player#readme", + "dependencies": { + "lodash": "^4.17.20", + "loglevel": "^1.7.0", + "webrtc-adapter": "^7.7.0" + }, + "devDependencies": { + "@babel/core": "^7.12.3", + "@babel/preset-env": "^7.12.1", + "@babel/register": "^7.12.1", + "babel-eslint": "^10.1.0", + "browser-sync": "^2.26.13", + "browserify": "^17.0.0", + "browserify-transform-tools": "^1.7.0", + "del": "^6.0.0", + "eslint": "^7.12.1", + "eslint-plugin-jest": "^24.1.0", + "estraverse-fb": "^1.3.2", + "grasp": "^0.6.0", + "gulp": "^4.0.2", + "gulp-autoprefixer": "^7.0.1", + "gulp-babel": "^8.0.0", + "gulp-clean-css": "^4.3.0", + "gulp-concat": "^2.6.1", + "gulp-connect": "^5.0.0", + "gulp-css-base64": "^2.0.0", + "gulp-html-to-js": "0.0.7", + "gulp-htmlmin": "^5.0.1", + "gulp-if": "^3.0.0", + "gulp-inject": "^5.0.5", + "gulp-sass": "^4.1.0", + "gulp-streamify": "^1.0.2", + "gulp-tap": "^2.0.0", + "gulp-uglify-es": "^2.0.0", + "gulp-using": "^0.1.1", + "gulp-util": "^3.0.8", + "jest": "^26.6.3", + "jest-junit": "^12.0.0", + "merge2": "^1.4.1", + "through2": "^4.0.2", + "vinyl": "^2.2.1", + "vinyl-source-stream": "^2.0.0" + }, + "jest-junit": { + "suiteName": "jest tests", + "outputDirectory": "tests/reports", + "outputName": "junit.xml" + } +} diff --git a/src/GenymotionInstance.js b/src/GenymotionInstance.js new file mode 100644 index 0000000..4d29a0f --- /dev/null +++ b/src/GenymotionInstance.js @@ -0,0 +1,830 @@ +'use strict'; + +// Plugins +const PeerConnectionStats = require('./plugins/PeerConnectionStats'); + +const log = require('loglevel'); +log.setDefaultLevel('debug'); + +/** + * Genymotion player instance. + * Initialize a player for a specific instance + */ +module.exports = class GenymotionInstance { + /** + * Player instance initialization. + * + * @param {HTMLElement} domRoot DOM element to attach the player to. + * @param {Object} options Instance configuration options. + */ + constructor(domRoot, options) { + this.timeoutCallbacks = []; + this.videoBackupStyleBackground = ''; + + // Options associated with this instance + this.options = options; + + // Websocket & WebRTC connection state + this.initialized = false; + this.reconnecting = false; + + // Enabled features + this.keyboardEventsEnabled = false; + this.touchEventsEnabled = false; + this.mouseEventsEnabled = false; + + // Websocket + this.webRTCWebsocket = null; + this.useWebsocketAsDataChannel = false; + + // DOM elements + this.root = domRoot; + this.video = this.getChildByClass(this.root, 'gm-video'); + this.wrapper = this.getChildByClass(this.root, 'gm-wrapper'); + this.videoWrapper = this.getChildByClass(this.root, 'gm-video-wrapper'); + this.stream = null; + + // Event callbacks + this.callbacks = {}; + + // WebRTC related attributes + this.peerConnection = null; + this.signalingDataChannel = null; + this.cameraSender = null; + this.microphoneSender = null; + this.sdpConstraints = { + offerToReceiveAudio: true, + offerToReceiveVideo: true, + }; + + // last accessed x/y position + this.x = 0; + this.y = 0; + + document.addEventListener('click', (event) => { + if (!this.hasSomeParentTheClass(event.target, 'gm-overlay') + && !event.target.classList.contains('gm-icon-button') + && !event.target.classList.contains('gm-dont-close')) { + this.emit('close-overlays'); + } + }); + } + + /** + * Create & dispatch a custom event. + * + * @param {string} name Event name. + * @param {Object} payload Event payload. + */ + dispatchEvent(name, payload) { + window.dispatchEvent(new CustomEvent(name, {detail: payload})); + } + + /** + * Find a child of a DOM element of given a class. + * + * @param {HTMLElement} element DOM element to search into. + * @param {string} className Name of the class to search for. + * @return {HTMLElement} The first DOM element found, or null. + */ + getChildByClass(element, className) { + for (let i = 0; i < element.childNodes.length; i++) { + const node = element.childNodes[i]; + if (node.classList && node.classList.contains(className)) { + return node; + } + + const child = this.getChildByClass(node, className); + if (child) { + return child; + } + } + return null; + } + + /** + * Register new callback to be executed when an event is emitted. + * + * @param {string} eventTag Tag of event to react to. + * @param {Function} callback Action to execute to handle the event. + */ + registerEventCallback(eventTag, callback) { + if (!this.callbacks[eventTag]) { + this.callbacks[eventTag] = []; + } + this.callbacks[eventTag].push(callback); + } + + /** + * Emit a new event. + * + * @param {string} eventTag Tag of the event. + * @param {Object} payload Event payload. + */ + emit(eventTag, payload) { + if (!this.callbacks[eventTag]) { + return; + } + + this.callbacks[eventTag].forEach((callback) => { + callback(payload); + }); + } + + /** + * Look for a class applied in a element parent tree. + * + * @param {HTMLElement} element DOM element to check. + * @param {string} className Class name to look for. + * @return {boolean} Whether or not the class has been found in the given element parents. + */ + hasSomeParentTheClass(element, className) { + if (element.classList && element.classList.contains(className)) { + return true; + } + return element.parentNode && this.hasSomeParentTheClass(element.parentNode, className); + } + + /** + * Check a websocket instance status. + * + * @param {WebSocket} webSocket websocket instance. + * @return {boolean} Whether or not the websocket is open. + */ + isWebsocketOpen(webSocket) { + return webSocket && webSocket instanceof WebSocket && webSocket.readyState === webSocket.OPEN; + } + + /** + * WebRTC channel ready callback. + */ + onWebRTCReady() { + this.webRTCConnectionRetryCount = 0; + this.openWebRTCConnection(); + } + + /** + * Open WebSocket and WebRTC connection. + */ + openWebRTCConnection() { + if (this.webRTCWebsocket) { + this.disconnect(); + this.reconnecting = true; + } + + this.webRTCWebsocket = new WebSocket(this.options.webRTCUrl); + this.webRTCWebsocket.onopen = this.sendAuthenticationToken.bind(this); + this.webRTCWebsocket.onmessage = this.onWebSocketMessage.bind(this); + this.webRTCWebsocket.onerror = this.onWebSocketMessage.bind(this); + this.webRTCWebsocket.binaryType = 'arraybuffer'; + + /** + * In case of unexpected close of the WebSocket connection, the handler will retry n times before dying + * For now we'll be using a lucky value until behaviour is further specified + */ + if (this.webRTCConnectionRetryCount <= 13) { + this.onConnectionClosed(); + } else { + log.error('Unable to establish connection to your instance.'); + } + } + + /** + * WebRTC / WebSocket connection closed callback. + * This will poll the WebRTC sequence until the WebSocket stops throwing the onclose event (unexpected quit). + */ + onConnectionClosed() { + this.webRTCWebsocket.onclose = (event) => { + this.video.style.background = this.videoBackupStyleBackground; + this.initialized = false; + log.debug('Error! Maybe your VM is not available yet? (' + event.code +') ' + event.reason); + + switch (event.code) { + case 1000: + case 1001: + case 1005: + log.debug('Closing websocket'); + this.dispatchEvent('closeConnection', {msg: 'Closing connection'}); + break; + + case 1002: + case 1003: + case 1006: + case 1007: + case 1008: + case 1009: + case 1010: + case 1011: + case 1012: + case 1013: + case 1014: + case 1015: { + // Might be interesting to be able to setup polling debounce in the object configuration (DOM / Frontend Portal) + this.dispatchEvent('closeConnectionUnavailable', {msg: 'Can\'t connect to the WebSocket'}); + log.debug('Retrying in 3 seconds...'); + + const timeout = setTimeout(() => { + this.openWebRTCConnection(); + }, 3000); + this.timeoutCallbacks.push(timeout); + this.webRTCConnectionRetryCount++; + break; + } + case 4242: // wrong token provided + this.dispatchEvent('closeWrongToken', {msg: 'Wrong token, can\'t establish connection'}); + break; + + case 4243: // token no longer valid + this.dispatchEvent('closeNoLongerValidToken', { + msg: 'The token provided is no longer valid', + }); + break; + + case 4244: // server is shutting down + this.dispatchEvent('closeServerShutdown', {msg: 'Server is shutting down...'}); + break; + + default: + this.dispatchEvent('defaultCloseConnection', {msg: 'Default close connection'}); + // Do nothing (for now) + break; + } + }; + } + + /** + * Send auhentication token through the WebSocket connection. + */ + sendAuthenticationToken() { + const tokenRequest = { + type: 'token', + token: this.options.token, + }; + + if (this.isWebsocketOpen(this.webRTCWebsocket)) { + this.webRTCWebsocket.send(JSON.stringify(tokenRequest)); + } + } + + /** + * Disconnect the current instance, closing any open data channels. + */ + disconnect() { + this.initialized = false; + + if (typeof this.camera !== 'undefined' && typeof this.camera.getClientVideoStream !== 'undefined') { + this.removeLocalStream(this.camera.getClientVideoStream()); + } + + if (this.webRTCWebsocket) { + this.webRTCWebsocket.close(); + this.webRTCWebsocket = null; + this.timeoutCallbacks.forEach((timeout) => { + clearTimeout(timeout); + }); + this.timeoutCallbacks = []; + } + + if (this.peerConnection) { + this.peerConnection.close(); + this.peerConnection = null; + } + + if (this.signalingDataChannel) { + this.signalingDataChannel.close(); + this.signalingDataChannel = null; + } + + if (typeof this.fileUpload !== 'undefined') { + const msg = {type: 'close'}; + this.fileUpload.loaderWorker.postMessage(msg); + } + } + + /** + * Send event to the instance through the Websocket connection. + * + * @param {Object} event Event to send. + */ + sendEvent(event) { + event = JSON.stringify(event); + + if (this.useWebsocketAsDataChannel) { + if (this.isWebsocketOpen(this.webRTCWebsocket)) { + this.webRTCWebsocket.send(event); + } + } else { + if (this.signalingDataChannel && this.signalingDataChannel.readyState === 'open') { + this.signalingDataChannel.send(event); + } else { + log.warn('cannot send event, signaling data channel closed'); + } + } + } + + /** + * Reconfigure & setup the peer-to-peer connection (SDP). + * Can be used anytime to renegotiate the SDP if necessary. + */ + renegotiateWebRTCConnection() { + // For safari we add audio & video before sending SDP to avoid empty SDP + const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent); + if (isSafari) { + this.peerConnection.addTransceiver('audio'); + this.peerConnection.addTransceiver('video'); + } + // creating SDP offer + this.peerConnection.createOffer( + this.setLocalDescription.bind(this), + this.onWebRTCConnectionError.bind(this), + this.sdpConstraints + ); + } + + /** + * Find RTCRtpSender corresponding RTCRtpTransceiver and set its direction. + * + * @param {RTCRtpSender} sender Peer (sender). + * @param {string} direction Transceiver direction. + */ + setTransceiverDirection(sender) { + // find transceiver that contains sender + this.peerConnection.getTransceivers().forEach((transceiver) => { + if (transceiver.sender === sender) { + transceiver.direction = 'sendrecv'; + } + }); + } + + /** + * Add a local stream and send it through SDP renegotiation. + * + * See https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addTrack + * and https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addStream + * + * @param {MediaStream} stream Stream to add. + */ + addLocalStream(stream) { + if (typeof this.peerConnection.addTrack === 'function') { + // If the new API "addTrack" is available, we use it + + /** + * If cameraSender or microphoneSender is defined, this means that we already added + * it to the PeerConnection. Since removeTrack() just remove the track + * from it, re-add it and switch back the RTCRtpTranceiver direction + * to send and recv. + */ + if (stream.getVideoTracks().length > 0) { + if (this.cameraSender) { + log.debug('Replacing video track on sender'); + this.cameraSender.replaceTrack(stream.getVideoTracks()[0]); + this.setTransceiverDirection(this.cameraSender, 'sendrecv'); + } else { + this.cameraSender = this.peerConnection.addTrack(stream.getVideoTracks()[0], + stream); + } + } + + if (this.options.microphone && stream.getAudioTracks().length > 0) { + if (this.microphoneSender) { + log.debug('Replacing audio track on sender'); + this.microphoneSender.replaceTrack(stream.getAudioTracks()[0]); + this.setTransceiverDirection(this.microphoneSender, 'sendrecv'); + } else { + this.microphoneSender = this.peerConnection.addTrack(stream.getAudioTracks()[0], + stream); + } + } + } else { + // Else if it is not available, we use the old "addStream" + this.peerConnection.addStream(stream); + } + this.renegotiateWebRTCConnection(); + } + + /** + * Remove a local stream and stop sending it through SDP renegotiation. + * + * See https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/removeTrack + * and https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/removeStream + * + * @param {MediaStream} stream Stream to stop and remove. + */ + removeLocalStream(stream) { + if (stream instanceof MediaStream) { + stream.getTracks().forEach((track) => { + track.stop(); + }); + // If the new API "removeTrack" is available, we use it + if (typeof this.peerConnection.addTrack === 'function') { + this.peerConnection.removeTrack(this.cameraSender); + if (this.microphoneSender) { + this.peerConnection.removeTrack(this.microphoneSender); + } + // Else if it is not available, we use the old "removeStream" + } else { + this.peerConnection.removeStream(stream); + } + this.renegotiateWebRTCConnection(); + } + } + + /** + * Creates a peer connection that connects through WebRTC to the instance. + */ + createPeerConnection() { + log.debug('Creating peer connection'); + + const iceServers = []; + + if (Object.keys(this.options.stun).length > 0) { + iceServers.push(this.options.stun); + } + + if (Object.keys(this.options.turn).length > 0) { + iceServers.push(this.options.turn); + } + + const config = { + iceServers: iceServers, + }; + + if (!this.peerConnection) { + try { + this.peerConnection = new RTCPeerConnection(config); + } catch (e) { + log.warn('Failed to create PeerConnection, exception:', e.message); + } + } else { + log.debug('Peer connection already exists'); + } + + if (typeof this.peerConnection.createDataChannel !== 'undefined') { + const dataChannelOptions = { + ordered: true, + }; + + this.signalingDataChannel = this.peerConnection.createDataChannel('events', dataChannelOptions); + + this.signalingDataChannel.onerror = (error) => { + log.warn('Data Channel Error:', error); + }; + + this.signalingDataChannel.onmessage = (event) => { + log.debug('Got Data Channel Message:', event.data); + }; + this.signalingDataChannel.onopen = () => { + log.debug('Data Channel opened'); + }; + + this.signalingDataChannel.onclose = () => { + log.debug('The Data Channel is Closed'); + }; + + this.peerConnection.ondatachannel = (event) => { + const answererDataChannel = event.channel; + answererDataChannel.onmessage = this.onDataChannelMessage.bind(this); + }; + } else { + this.useWebsocketAsDataChannel = true; + } + + this.peerConnection.onicecandidate = (event) => { + if (typeof event.candidate === 'undefined') { + // Nothing we can do + return; + } + + if (event.candidate) { + this.sendIceCandidate(event.candidate); + } else { + log.debug('All candidates ready'); + } + }; + + this.peerConnection.ontrack = (event) => { + log.debug('Received track:', event.track.kind); + + if (event.track.kind !== 'video') { + return; + } + + log.debug('Added remote video track using ontrack'); + this.video.srcObject = event.streams[0]; + this.video.setAttribute('playsinline', true); // needed on iOs + this.stream = event.streams[0]; + + // Get the PeerConnection Statistics after 3 seconds + new PeerConnectionStats(this, this.peerConnection, 3000); + + this.videoBackupStyleBackground = this.video.style.background; + this.video.style.background = 'transparent'; + + if (this.touchEventsEnabled) { + this.touchEvents.addTouchCallbacks(); + } + + if (this.mouseEventsEnabled) { + this.mouseEvents.addMouseCallbacks(); + } + + if (this.keyboardEventsEnabled) { + this.keyboardEvents.addKeyboardCallbacks(); + } + + const playWithSound = this.video.play(); // needed on Safari (web & iOs) + if (!playWithSound) { + return; + } + + playWithSound.then(() => { + log.debug('Playing video with sound enabled'); + this.dispatchEvent('video', {msg: 'play automatically allowed with sound'}); + }).catch(() => { + log.debug('Can\'t play video with sound enabled'); + this.dispatchEvent('video', {msg: 'play with sound denied'}); + this.video.muted = true; + const playWithoutSound = this.video.play(); + playWithoutSound.then(() => { + log.debug('Playing video with sound disabled'); + this.dispatchEvent('video', {msg: 'play automatically allowed without sound'}); + const popup = document.createElement('div'); + popup.classList.add('gm-click-to-unmute'); + popup.innerHTML = 'By default, the sound has been turned off, ' + + 'please click anywhere to re-enable audio'; + this.videoWrapper.prepend(popup); + const addSound = () => { + this.video.muted = false; + this.video.removeEventListener('click', addSound); + this.video.removeEventListener('touchend', addSound); + this.dispatchEvent('video', {msg: 'sound manually allowed by click'}); + popup.remove(); + log.debug('Playing video with sound enabled has been authorized due to user click'); + }; + this.video.addEventListener('click', addSound); + this.video.addEventListener('touchend', addSound); + }).catch(() => { + log.debug('Can\'t play video, even with sound disabled'); + this.dispatchEvent('video', {msg: 'play denied even without sound'}); + const div = document.createElement('div'); + this.classList.add('gm-click-to-display'); + this.classList.add('gm-video-overlay'); + this.videoWrapper.prepend(div); + const allowPlay = () => { + this.video.play(); + div.remove(); + this.dispatchEvent('video', {msg: 'play manually allowed by click'}); + log.debug('Playing video with sound disabled has been authorized due to user click'); + }; + div.addEventListener('click', allowPlay); + div.addEventListener('touchend', allowPlay); + }); + }); + }; + + this.peerConnection.oniceconnectionstatechange = () => { + const iceConnectionState = + this.peerConnection ? this.peerConnection.iceConnectionState : 'No peerConnection'; + log.debug('iceConnectionState: ', iceConnectionState); + this.dispatchEvent('iceConnectionState', {msg: iceConnectionState}); + + if (iceConnectionState !== 'failed') { + return; + } + + let message = '
Aw, snap!
Connection failed.

Check your internet ' + + 'connection & firewall rules.{DOC_AVAILABLE}

'; + const div = document.createElement('div'); + div.classList.add('gm-overlay-cant-connect'); + div.classList.add('gm-video-overlay'); + this.videoWrapper.prepend(div); + if (this.options.connectionFailedURL) { + message = message.replace( + '{DOC_AVAILABLE}', + '
See help to setup TURN configuration.' + ); + const openDocumentationLink = () => { + this.dispatchEvent('iceConnectionStateDocumentation', {msg: 'clicked'}); + div.remove(); + window.open(this.options.connectionFailedURL, '_blank'); + }; + div.addEventListener('click', openDocumentationLink); + div.addEventListener('touchend', openDocumentationLink); + } else { + message = message.replace('{DOC_AVAILABLE}', ''); + } + + div.innerHTML = message; + }; + + this.peerConnection.onconnectionstatechange = () => { + log.debug('ConnectionState changed:', this.peerConnection.iceConnectionState); + if (this.peerConnection.iceConnectionState === 'disconnected') { + this.onWebRTCReady(); + } + }; + + this.peerConnection.onnegotiationneeded = () => { + log.debug('on Negotiation needed'); + }; + + this.renegotiateWebRTCConnection(); + } + + /** + * Send any ice candidates to the other peer. + * + * @param {RTCIceCandidate} iceCandidate Candidate to send. + */ + sendIceCandidate(iceCandidate) { + if (this.isWebsocketOpen(this.webRTCWebsocket)) { + this.webRTCWebsocket.send(JSON.stringify(iceCandidate)); + } + } + + /** + * Called when a PeerConnection receives a description. + * + * @param {RTCSessionDescription} description Peer connection session description. + */ + setLocalDescription(description) { + this.peerConnection.setLocalDescription(description); + if (this.isWebsocketOpen(this.webRTCWebsocket)) { + this.webRTCWebsocket.send(JSON.stringify(description)); + } + } + + /** + * Called when the WebRTC WebSocket socket receives a message. + * + * @param {Event} message WebRTC message. + */ + onWebSocketMessage(message) { + let data = null; + + try { + data = JSON.parse(message.data); + } catch (error) { + return; + } + + if (!data) { + return; + } + + if (data.sdp) { + try { + const sdp = new RTCSessionDescription(data); + this.peerConnection.setRemoteDescription( + sdp, + this.onWebRTCConnectionEstablished.bind(this), + this.onWebRTCConnectionError.bind(this) + ); + } catch (error) { + log.warn('Failed to create SDP ', error.message); + } + } else if (data.candidate) { + try { + const candidate = new RTCIceCandidate(data); + this.peerConnection.addIceCandidate(candidate); + } catch (error) { + log.warn('Failed to create ICE ', error.message); + } + } else if (data.connection) { + this.createPeerConnection(); + } else { + this.handleMessage(data); + } + } + + /** + * Called when both local and remote SDP have been set. + */ + onWebRTCConnectionEstablished() { + log.debug('WebRTC connection success'); + + if (this.initialized) { + return; + } + + this.initialized = true; + if (this.reconnecting) { + this.reconnecting = false; + } else { + this.dispatchEvent('successConnection', {msg: 'Connection established'}); + } + + if (this.fileUpload) { + const msg = { + type: 'address', + fileUploadAddress: this.options.fileUploadUrl, + token: this.options.token, + }; + + if (this.fileUpload.loaderWorker) { + this.fileUpload.loaderWorker.postMessage(msg); + } + } + } + + /** + * WebRTC connection error. + * + * @param {string} code Error code. + */ + onWebRTCConnectionError(code) { + log.debug('Failure callback:', code); + } + + /** + * Parse & process data events received from WebRTC data channel. + * + * @param {Event} event WebRTC event. + */ + onDataChannelMessage(event) { + const data = JSON.parse(event.data); + this.handleMessage(data); + } + + /** + * Process WebRTC message. + * + * @param {Object} data Message payload. + */ + handleMessage(data) { + if (data.type === 'USERS') { + if (data.code === 'SUCCESS') { + this.dispatchEvent('userListUpdated', {msg: data.message}); + } + } else if (data.type === 'VERSION') { + if (data.code === 'SUCCESS') { + const versionNumber = this.getChildByClass(this.root, 'gm-version-number'); + if (versionNumber) { + versionNumber.innerHTML = data.message; + } + } + } else if (data.type === 'CAPABILITIES') { + [{ + widget: this.battery, + capability: data.message.battery, + }, { + widget: this.camera, + capability: data.message.camera, + }, { + widget: this.gps, + capability: data.message.gps, + }, { + widget: this.identifiers, + capability: data.message.identifiers, + }, { + widget: this.network, + capability: data.message.network, + }, { + widget: this.phone, + capability: data.message.phone, + }, { + widget: this.diskIO, + capability: data.message.diskIO, + }, { + widget: this.buttonsEvents, + capability: data.message.accelerometer, + enable: (widget) => { + widget.enableRotation(); + }, + disable: (widget) => { + widget.disableRotation(); + }, + }, { + widget: this.fileUpload, + capability: data.message.systemPatcher, + enable: (widget) => { + widget.setAvailability(true); + }, + disable: (widget) => { + widget.setAvailability(false); + }, + }].forEach((feature) => { + if (typeof feature.widget !== 'undefined') { + if (feature.capability === false) { + if (feature.disable) { + feature.disable(feature.widget); + } else { + feature.widget.disable(); + } + } else { + if (feature.enable) { + feature.enable(feature.widget); + } else { + feature.widget.enable(); + } + } + } + }); + } + + // Emit message to anyone who wants to listen + if (data.code === 'SUCCESS') { + this.emit(data.type, data.message); + } + } +}; diff --git a/src/GenymotionManager.js b/src/GenymotionManager.js new file mode 100644 index 0000000..8b7236f --- /dev/null +++ b/src/GenymotionManager.js @@ -0,0 +1,234 @@ +'use strict'; + +const GenymotionInstance = require('./GenymotionInstance'); +const defaultsDeep = require('lodash/defaultsDeep'); + +// Plugins +const GPS = require('./plugins/GPS'); +const CoordinateUtils = require('./plugins/CoordinateUtils'); +const MouseEvents = require('./plugins/MouseEvents'); +const MultiTouchEvents = require('./plugins/MultiTouchEvents'); +const ButtonsEvents = require('./plugins/ButtonsEvents'); +const Fullscreen = require('./plugins/Fullscreen'); +const KeyboardEvents = require('./plugins/KeyboardEvents'); +const Clipboard = require('./plugins/Clipboard'); +const FileUpload = require('./plugins/FileUpload'); +const Camera = require('./plugins/Camera'); +const Battery = require('./plugins/Battery'); +const StreamBitrate = require('./plugins/StreamBitrate'); +const Screencast = require('./plugins/Screencast'); +const Identifiers = require('./plugins/Identifiers'); +const Network = require('./plugins/Network'); +const Phone = require('./plugins/Phone'); +const StreamResolution = require('./plugins/StreamResolution'); +const IOThrottling = require('./plugins/IOThrottling'); + +const log = require('loglevel'); +log.setDefaultLevel('debug'); + +// Templates are loaded dynamically from the `templates` folder +const TEMPLATE_JS = 'genymotion-js'; +const TEMPLATE_CSS = 'genymotion-css'; + +// Default options +const defaultOptions = { + template: 'player', + touch: true, + mouse: true, + volume: true, + rotation: true, + navbar: true, + power: true, + keyboard: true, + fullscreen: true, + camera: true, + microphone: false, + fileUpload: true, + streamBitrate: false, + clipboard: true, + battery: true, + gps: true, + gpsSpeedSupport: false, + capture: true, + identifiers: true, + network: true, + baseband: false, + phone: true, + streamResolution: true, + diskIO: true, + translateHomeKey: false, + token: '', + i18n: {}, + stun: { + urls: [ + // TODO: remove what we don't have + 'stun:stun-eu.genymotion.com:80', + 'stun:stun-eu.genymotion.com:443', + 'stun:stun-eu.genymotion.com:3478', + 'stun:stun-eu.genymotion.com:5349', + 'stun:stun-na.genymotion.com:80', + 'stun:stun-na.genymotion.com:443', + 'stun:stun-na.genymotion.com:3478', + 'stun:stun-na.genymotion.com:5349' + ], + }, + connectionFailedURL: '', + turn: {}, +}; + +/** + * Setup & create instances of the Genymotion player + */ +module.exports = class GenymotionManager { + constructor() { + this.instances = []; + /* global GEN_TEMPLATES */ + this.templates = GEN_TEMPLATES; + } + + /** + * Setup a device player instance in the given dom element, for the Genymotion Cloud instance identified by its instanceWebRTCUrl. + * + * @param {HTMLElement|string} dom The DOM element (or its ID) to setup the device player into. + * @param {string} webRTCUrl WebRTC URL of the instance. + * @param {Object} options Various configuration options. + * @param {string} options.template Template to use. Default: 'player'. + * @param {boolean} options.touch Touch support activated. Default: true. + * @param {boolean} options.mouse Mouse support activated. Default: true. + * @param {boolean} options.volume Audio volume control support activated. Default: true. + * @param {boolean} options.rotation Screen rotation support activated. Default: true. + * @param {boolean} options.navbar Android navbar support activated. Default: true. + * @param {boolean} options.power Power control support activated. Default: true. + * @param {boolean} options.keyboard Keyboad support activated. Default: true. + * @param {boolean} options.fullscreen Fullscreen support activated. Default: true. + * @param {boolean} options.camera Camera support activated. Default: true. + * @param {boolean} options.microphone Microphone support activated. Default: false. + * @param {boolean} options.fileUpload File upload support activated. Default: true. + * @param {string} options.fileUploadUrl File upload URL. Required if fileUpload===true. + * @param {boolean} options.streamBitrate Stream bitrate control support activated. Default: false. + * @param {boolean} options.clipboard Clipboard forwarding support activated. Default: true. + * @param {boolean} options.battery Battery support activated. Default: true. + * @param {boolean} options.gps GPS support activated. Default: true. + * @param {boolean} options.gpsSpeedSupport GPS speed support activated. Default: false. + * @param {boolean} options.capture Screen capture support activated. Default: true. + * @param {boolean} options.identifiers Identifiers (IMEI, etc...) support activated. Default: true. + * @param {boolean} options.network Network throttling support activated. Default: true. + * @param {boolean} options.baseband Baseband controll support activated. Default: false. + * @param {boolean} options.phone Baseband support activated. Default: true. + * @param {boolean} options.streamResolution Stream resolution control support activated. Default: true. + * @param {boolean} options.diskIO Disk I/O throttling support activated. Default: true. + * @param {boolean} options.translateHomeKey Whether or not the HOME key button should be decompose to META + ENTER. Default: false. + * @param {string} options.token Instance access token (JWT). Default: ''. + * @param {Object} options.i18n Translations keys for the UI. Default: {}. + * @param {Object} options.stun WebRTC STUN servers configuration. + * @param {Array} options.stun.urls WebRTC STUN servers URLs. + * @param {string} options.connectionFailedURL Redirection page in case of connection establishment error. + * @param {Object} options.turn WebRTC TURN servers configuration. + * @param {Array} options.turn.urls WebRTC TURN servers URLs. + * @param {string} options.turn.username WebRTC TURN servers username. + * @param {string} options.turn.credential WebRTC TURN servers password. + * @param {boolean} options.turn.default Whether or not we should use the TURN servers by default. Default: false. + * @return {GenymotionInstance} The Genymotion instance. + */ + setupInstance(dom, webRTCUrl, options) { + if (typeof dom === 'string') { + dom = document.getElementById(dom); + } + + if (typeof options === 'undefined') { + options = {}; + } + options = defaultsDeep(options, defaultOptions); + options.webRTCUrl = webRTCUrl; + // if we have at least one button to setup, we will instantiate the "buttons" plugin + options.buttons = options.volume || options.rotation || options.navbar || options.power; + + log.debug('Creating genymotion display on ' + webRTCUrl); + dom.classList.add('gm-player-instance'); + dom.classList.add('gm-template-' + options.template); + document.body.classList.add('gm-template-' + options.template + '-body'); + + return this.loadTemplate(dom, this.templates[options.template], options); + } + + /** + * Loads the selected template. + * + * @param {HTMLElement} dom The DOM element to setup the device player into. + * @param {string} template Template to use. + * @param {Object} options Various configuration options. + * @return {GenymotionInstance} The Genymotion instance. + */ + loadTemplate(dom, template, options) { + const head = document.getElementsByTagName('head')[0]; + const scriptId = TEMPLATE_JS + '-' + options.template; + const styleId = TEMPLATE_CSS + '-' + options.template; + + // Handle template JS + if (!document.getElementById(scriptId)) { + const script = document.createElement('script'); + script.id = scriptId; + script.text = template.js; + head.appendChild(script); + } + + // Handle template CSS + if (!document.getElementById(styleId)) { + const style = document.createElement('style'); + style.id = styleId; + style.appendChild(document.createTextNode(template.css)); + head.appendChild(style); + } + + // Handle template dom + dom.innerHTML = template.html; + + // Kick off next phase of setup + return this.addPlugins(dom, options); + } + + /** + * Initialize all the needed plugins. + * + * @param {HTMLElement} dom The DOM element to setup the device player into. + * @param {Object} options Various configuration options. + * @return {GenymotionInstance} The Genymotion instance. + */ + addPlugins(dom, options) { + const instance = new GenymotionInstance(dom, options); + this.instances.push(instance); + + const pluginInitMap = [ + {enabled: options.touch || options.mouse, class: CoordinateUtils}, + {enabled: options.mouse, class: MouseEvents}, + {enabled: options.touch, class: MultiTouchEvents}, + {enabled: options.fullscreen, class: Fullscreen}, + {enabled: options.keyboard, class: KeyboardEvents}, + {enabled: options.clipboard, class: Clipboard, params: [options.i18n]}, + {enabled: options.fileUpload, class: FileUpload, params: [options.i18n]}, + {enabled: options.camera, class: Camera, params: [options.i18n]}, + {enabled: options.battery, class: Battery, params: [options.i18n]}, + {enabled: options.streamBitrate, class: StreamBitrate, params: [options.i18n]}, + {enabled: options.gps, class: GPS, params: [options.i18n, options.gpsSpeedSupport]}, + {enabled: options.capture, class: Screencast, params: [options.i18n]}, + {enabled: options.identifiers, class: Identifiers, params: [options.i18n]}, + {enabled: options.network, class: Network, params: [options.i18n, options.baseband]}, + {enabled: options.phone, class: Phone, params: [options.i18n]}, + {enabled: options.streamResolution, class: StreamResolution}, + {enabled: options.diskIO, class: IOThrottling, params: [options.i18n]}, + {enabled: options.buttons, class: ButtonsEvents, params: [options.i18n, options.translateHomeKey]}, + ]; + + pluginInitMap.forEach((plugin) => { + const args = plugin.params || []; + + if (plugin.enabled) { + new plugin.class(instance, ...args); + } + }); + + instance.onWebRTCReady(); + + return instance; + } +}; diff --git a/src/assets/images/hq-over.png b/src/assets/images/hq-over.png new file mode 100644 index 0000000..8eab8d6 Binary files /dev/null and b/src/assets/images/hq-over.png differ diff --git a/src/assets/images/hq.png b/src/assets/images/hq.png new file mode 100644 index 0000000..731dd5a Binary files /dev/null and b/src/assets/images/hq.png differ diff --git a/src/assets/images/ic-battery_active.svg b/src/assets/images/ic-battery_active.svg new file mode 100644 index 0000000..50ac3f6 --- /dev/null +++ b/src/assets/images/ic-battery_active.svg @@ -0,0 +1,12 @@ + + + + ic-battery_active + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic-battery_active_black.svg b/src/assets/images/ic-battery_active_black.svg new file mode 100644 index 0000000..117093d --- /dev/null +++ b/src/assets/images/ic-battery_active_black.svg @@ -0,0 +1,12 @@ + + + + ic-battery_active_black + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic-battery_empty.svg b/src/assets/images/ic-battery_empty.svg new file mode 100644 index 0000000..52991b8 --- /dev/null +++ b/src/assets/images/ic-battery_empty.svg @@ -0,0 +1,34 @@ + + + + ic-battery_inactive + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic-battery_inactive.svg b/src/assets/images/ic-battery_inactive.svg new file mode 100644 index 0000000..7946ace --- /dev/null +++ b/src/assets/images/ic-battery_inactive.svg @@ -0,0 +1,12 @@ + + + + ic-battery_inactive + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic-close-popup-default.svg b/src/assets/images/ic-close-popup-default.svg new file mode 100644 index 0000000..1f9fa55 --- /dev/null +++ b/src/assets/images/ic-close-popup-default.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/src/assets/images/ic-close-popup-hover.svg b/src/assets/images/ic-close-popup-hover.svg new file mode 100644 index 0000000..07198ed --- /dev/null +++ b/src/assets/images/ic-close-popup-hover.svg @@ -0,0 +1,10 @@ + + + + + + diff --git a/src/assets/images/ic-nav_android_back_active.svg b/src/assets/images/ic-nav_android_back_active.svg new file mode 100644 index 0000000..9671847 --- /dev/null +++ b/src/assets/images/ic-nav_android_back_active.svg @@ -0,0 +1,12 @@ + + + + ic-nav_android_active + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic-nav_android_back_active_black.svg b/src/assets/images/ic-nav_android_back_active_black.svg new file mode 100644 index 0000000..8181559 --- /dev/null +++ b/src/assets/images/ic-nav_android_back_active_black.svg @@ -0,0 +1,12 @@ + + + + ic-nav_android_active_black + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic-nav_android_back_inactive.svg b/src/assets/images/ic-nav_android_back_inactive.svg new file mode 100644 index 0000000..1c1ad24 --- /dev/null +++ b/src/assets/images/ic-nav_android_back_inactive.svg @@ -0,0 +1,12 @@ + + + + ic-nav_android_active + Created with Sketch. + + + + + + + diff --git a/src/assets/images/ic-nav_android_home_active.svg b/src/assets/images/ic-nav_android_home_active.svg new file mode 100644 index 0000000..c279d01 --- /dev/null +++ b/src/assets/images/ic-nav_android_home_active.svg @@ -0,0 +1,12 @@ + + + + ic-nav_android_home_active_black + Created with Sketch. + + + + + + + diff --git a/src/assets/images/ic-nav_android_home_active_black.svg b/src/assets/images/ic-nav_android_home_active_black.svg new file mode 100644 index 0000000..da1ff67 --- /dev/null +++ b/src/assets/images/ic-nav_android_home_active_black.svg @@ -0,0 +1,12 @@ + + + + ic-nav_android_home_active_black + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic-nav_android_home_inactive.svg b/src/assets/images/ic-nav_android_home_inactive.svg new file mode 100644 index 0000000..a845b80 --- /dev/null +++ b/src/assets/images/ic-nav_android_home_inactive.svg @@ -0,0 +1,12 @@ + + + + ic-nav_android_home_active_black + Created with Sketch. + + + + + + + diff --git a/src/assets/images/ic-nav_android_multiapp_active.svg b/src/assets/images/ic-nav_android_multiapp_active.svg new file mode 100644 index 0000000..30a8036 --- /dev/null +++ b/src/assets/images/ic-nav_android_multiapp_active.svg @@ -0,0 +1,12 @@ + + + + ic-nav_android_multiapp_active + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic-nav_android_multiapp_active_black.svg b/src/assets/images/ic-nav_android_multiapp_active_black.svg new file mode 100644 index 0000000..dec8656 --- /dev/null +++ b/src/assets/images/ic-nav_android_multiapp_active_black.svg @@ -0,0 +1,12 @@ + + + + ic-nav_android_multiapp_active_black + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic-nav_android_multiapp_inactive.svg b/src/assets/images/ic-nav_android_multiapp_inactive.svg new file mode 100644 index 0000000..144bf49 --- /dev/null +++ b/src/assets/images/ic-nav_android_multiapp_inactive.svg @@ -0,0 +1,12 @@ + + + + ic-nav_android_multiapp_inactive + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic-resolution_active.svg b/src/assets/images/ic-resolution_active.svg new file mode 100644 index 0000000..5c54013 --- /dev/null +++ b/src/assets/images/ic-resolution_active.svg @@ -0,0 +1,12 @@ + + + + ic-resolution_active + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic-resolution_active_black.svg b/src/assets/images/ic-resolution_active_black.svg new file mode 100644 index 0000000..fe85a92 --- /dev/null +++ b/src/assets/images/ic-resolution_active_black.svg @@ -0,0 +1,12 @@ + + + + ic-resolution_active_black + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic-resolution_inactive.svg b/src/assets/images/ic-resolution_inactive.svg new file mode 100644 index 0000000..1eb88ca --- /dev/null +++ b/src/assets/images/ic-resolution_inactive.svg @@ -0,0 +1,12 @@ + + + + ic-resolution_inactive + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic-screencast_default.svg b/src/assets/images/ic-screencast_default.svg new file mode 100644 index 0000000..195bee7 --- /dev/null +++ b/src/assets/images/ic-screencast_default.svg @@ -0,0 +1,7 @@ + + + + + diff --git a/src/assets/images/ic-screencast_disabled.svg b/src/assets/images/ic-screencast_disabled.svg new file mode 100644 index 0000000..bda60ca --- /dev/null +++ b/src/assets/images/ic-screencast_disabled.svg @@ -0,0 +1,7 @@ + + + + + diff --git a/src/assets/images/ic-screenshot_active.svg b/src/assets/images/ic-screenshot_active.svg new file mode 100644 index 0000000..2e0c41c --- /dev/null +++ b/src/assets/images/ic-screenshot_active.svg @@ -0,0 +1,22 @@ + + + + ic-screenshot_active + Created with Sketch. + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic-screenshot_active_black.svg b/src/assets/images/ic-screenshot_active_black.svg new file mode 100644 index 0000000..316af4d --- /dev/null +++ b/src/assets/images/ic-screenshot_active_black.svg @@ -0,0 +1,22 @@ + + + + ic-screenshot_active_black + Created with Sketch. + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic-screenshot_default.svg b/src/assets/images/ic-screenshot_default.svg new file mode 100644 index 0000000..87444ae --- /dev/null +++ b/src/assets/images/ic-screenshot_default.svg @@ -0,0 +1,9 @@ + + + + + diff --git a/src/assets/images/ic-screenshot_disabled.svg b/src/assets/images/ic-screenshot_disabled.svg new file mode 100644 index 0000000..e970f66 --- /dev/null +++ b/src/assets/images/ic-screenshot_disabled.svg @@ -0,0 +1,9 @@ + + + + + diff --git a/src/assets/images/ic-screenshot_inactive.svg b/src/assets/images/ic-screenshot_inactive.svg new file mode 100644 index 0000000..3473b0c --- /dev/null +++ b/src/assets/images/ic-screenshot_inactive.svg @@ -0,0 +1,22 @@ + + + + ic-screenshot_inactive + Created with Sketch. + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_arrow_rotation_left.svg b/src/assets/images/ic_arrow_rotation_left.svg new file mode 100644 index 0000000..e4e6dc9 --- /dev/null +++ b/src/assets/images/ic_arrow_rotation_left.svg @@ -0,0 +1,14 @@ + + + + ic_arrow_rotation_left + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_arrow_rotation_right.svg b/src/assets/images/ic_arrow_rotation_right.svg new file mode 100644 index 0000000..1ffe89a --- /dev/null +++ b/src/assets/images/ic_arrow_rotation_right.svg @@ -0,0 +1,14 @@ + + + + ic_arrow_rotation_right + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_baseband_active.svg b/src/assets/images/ic_baseband_active.svg new file mode 100644 index 0000000..6b68030 --- /dev/null +++ b/src/assets/images/ic_baseband_active.svg @@ -0,0 +1,12 @@ + + + + ic_baseband_active + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_baseband_active_black.svg b/src/assets/images/ic_baseband_active_black.svg new file mode 100644 index 0000000..c2ead57 --- /dev/null +++ b/src/assets/images/ic_baseband_active_black.svg @@ -0,0 +1,12 @@ + + + + ic_baseband_active_black + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_baseband_inactive.svg b/src/assets/images/ic_baseband_inactive.svg new file mode 100644 index 0000000..88e9458 --- /dev/null +++ b/src/assets/images/ic_baseband_inactive.svg @@ -0,0 +1,12 @@ + + + + ic_baseband_inactive + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_camera_active.svg b/src/assets/images/ic_camera_active.svg new file mode 100644 index 0000000..e61face --- /dev/null +++ b/src/assets/images/ic_camera_active.svg @@ -0,0 +1,15 @@ + + + + ic_camera_active + Created with Sketch. + + + + + + + + + + diff --git a/src/assets/images/ic_camera_active_black.svg b/src/assets/images/ic_camera_active_black.svg new file mode 100644 index 0000000..3cea125 --- /dev/null +++ b/src/assets/images/ic_camera_active_black.svg @@ -0,0 +1,15 @@ + + + + ic_camera_active_black + Created with Sketch. + + + + + + + + + + diff --git a/src/assets/images/ic_camera_inactive.svg b/src/assets/images/ic_camera_inactive.svg new file mode 100644 index 0000000..d8e541f --- /dev/null +++ b/src/assets/images/ic_camera_inactive.svg @@ -0,0 +1,15 @@ + + + + ic_camera_active + Created with Sketch. + + + + + + + + + + diff --git a/src/assets/images/ic_click_to_display_default.svg b/src/assets/images/ic_click_to_display_default.svg new file mode 100644 index 0000000..dee5fc2 --- /dev/null +++ b/src/assets/images/ic_click_to_display_default.svg @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/ic_click_to_display_hover.svg b/src/assets/images/ic_click_to_display_hover.svg new file mode 100644 index 0000000..176f66d --- /dev/null +++ b/src/assets/images/ic_click_to_display_hover.svg @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/ic_clipboard_active.svg b/src/assets/images/ic_clipboard_active.svg new file mode 100644 index 0000000..d0856f9 --- /dev/null +++ b/src/assets/images/ic_clipboard_active.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/images/ic_clipboard_inactive.svg b/src/assets/images/ic_clipboard_inactive.svg new file mode 100644 index 0000000..bc610c5 --- /dev/null +++ b/src/assets/images/ic_clipboard_inactive.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/images/ic_cloud_upload.svg b/src/assets/images/ic_cloud_upload.svg new file mode 100644 index 0000000..c7c8232 --- /dev/null +++ b/src/assets/images/ic_cloud_upload.svg @@ -0,0 +1,12 @@ + + + + +Group 5 +Created with Sketch. + + diff --git a/src/assets/images/ic_cloud_upload_congralutation.svg b/src/assets/images/ic_cloud_upload_congralutation.svg new file mode 100644 index 0000000..0ac066b --- /dev/null +++ b/src/assets/images/ic_cloud_upload_congralutation.svg @@ -0,0 +1,25 @@ + + + + +Group 5 +Created with Sketch. + + + + + + + + + + + + + + diff --git a/src/assets/images/ic_cloud_upload_failed.svg b/src/assets/images/ic_cloud_upload_failed.svg new file mode 100644 index 0000000..3a1e52e --- /dev/null +++ b/src/assets/images/ic_cloud_upload_failed.svg @@ -0,0 +1,23 @@ + + + + Group 2 + Created with Sketch. + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_diskIO_active.svg b/src/assets/images/ic_diskIO_active.svg new file mode 100644 index 0000000..60333cc --- /dev/null +++ b/src/assets/images/ic_diskIO_active.svg @@ -0,0 +1,34 @@ + + + + ic_diskIO_active + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_diskIO_active_black.svg b/src/assets/images/ic_diskIO_active_black.svg new file mode 100644 index 0000000..c2dd0bd --- /dev/null +++ b/src/assets/images/ic_diskIO_active_black.svg @@ -0,0 +1,34 @@ + + + + ic_diskIO_active_black + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_diskIO_inactive.svg b/src/assets/images/ic_diskIO_inactive.svg new file mode 100644 index 0000000..88a6363 --- /dev/null +++ b/src/assets/images/ic_diskIO_inactive.svg @@ -0,0 +1,34 @@ + + + + ic_diskIO_inactive + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_error_default.svg b/src/assets/images/ic_error_default.svg new file mode 100644 index 0000000..3eb22a4 --- /dev/null +++ b/src/assets/images/ic_error_default.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/images/ic_fullscreen_active.svg b/src/assets/images/ic_fullscreen_active.svg new file mode 100644 index 0000000..d6b58e1 --- /dev/null +++ b/src/assets/images/ic_fullscreen_active.svg @@ -0,0 +1,39 @@ + + + + ic_fullscreen_active + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_fullscreen_active_black.svg b/src/assets/images/ic_fullscreen_active_black.svg new file mode 100644 index 0000000..0f143fc --- /dev/null +++ b/src/assets/images/ic_fullscreen_active_black.svg @@ -0,0 +1,39 @@ + + + + ic_fullscreen_active_black + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_fullscreen_exit_active.svg b/src/assets/images/ic_fullscreen_exit_active.svg new file mode 100644 index 0000000..f556bfd --- /dev/null +++ b/src/assets/images/ic_fullscreen_exit_active.svg @@ -0,0 +1,39 @@ + + + + ic_fullscreen_exit_active + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_fullscreen_exit_active_black.svg b/src/assets/images/ic_fullscreen_exit_active_black.svg new file mode 100644 index 0000000..3d6368f --- /dev/null +++ b/src/assets/images/ic_fullscreen_exit_active_black.svg @@ -0,0 +1,39 @@ + + + + ic_fullscreen_exit_active_black + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/images/ic_fullscreen_exit_inactive.svg b/src/assets/images/ic_fullscreen_exit_inactive.svg new file mode 100644 index 0000000..a69ca35 --- /dev/null +++ b/src/assets/images/ic_fullscreen_exit_inactive.svg @@ -0,0 +1,51 @@ + + + + ic_fullscreen_exit_inactive + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_fullscreen_inactive.svg b/src/assets/images/ic_fullscreen_inactive.svg new file mode 100644 index 0000000..1ec2169 --- /dev/null +++ b/src/assets/images/ic_fullscreen_inactive.svg @@ -0,0 +1,39 @@ + + + + ic_fullscreen_inactive + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_icon_mute.svg b/src/assets/images/ic_icon_mute.svg new file mode 100644 index 0000000..d69accd --- /dev/null +++ b/src/assets/images/ic_icon_mute.svg @@ -0,0 +1 @@ + diff --git a/src/assets/images/ic_icon_power_active.svg b/src/assets/images/ic_icon_power_active.svg new file mode 100644 index 0000000..5d0d8e1 --- /dev/null +++ b/src/assets/images/ic_icon_power_active.svg @@ -0,0 +1,12 @@ + + + + ic_icon_power_inactive + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_icon_power_inactive.svg b/src/assets/images/ic_icon_power_inactive.svg new file mode 100644 index 0000000..7771832 --- /dev/null +++ b/src/assets/images/ic_icon_power_inactive.svg @@ -0,0 +1,12 @@ + + + + ic_icon_power_inactive copy + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_icon_power_inactive_black.svg b/src/assets/images/ic_icon_power_inactive_black.svg new file mode 100644 index 0000000..bab7ae5 --- /dev/null +++ b/src/assets/images/ic_icon_power_inactive_black.svg @@ -0,0 +1,12 @@ + + + + ic_icon_power_inactive_black + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_id_active.svg b/src/assets/images/ic_id_active.svg new file mode 100644 index 0000000..ce09881 --- /dev/null +++ b/src/assets/images/ic_id_active.svg @@ -0,0 +1,23 @@ + + + + ic_id_active + Created with Sketch. + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_id_active_black.svg b/src/assets/images/ic_id_active_black.svg new file mode 100644 index 0000000..6bd534a --- /dev/null +++ b/src/assets/images/ic_id_active_black.svg @@ -0,0 +1,23 @@ + + + + ic_id_active_black + Created with Sketch. + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_id_inactive.svg b/src/assets/images/ic_id_inactive.svg new file mode 100644 index 0000000..9dd07af --- /dev/null +++ b/src/assets/images/ic_id_inactive.svg @@ -0,0 +1,23 @@ + + + + ic_id_inactive + Created with Sketch. + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_installation_active.svg b/src/assets/images/ic_installation_active.svg new file mode 100644 index 0000000..f046c26 --- /dev/null +++ b/src/assets/images/ic_installation_active.svg @@ -0,0 +1,12 @@ + + + + ic_installation_active + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_installation_active_black.svg b/src/assets/images/ic_installation_active_black.svg new file mode 100644 index 0000000..20ea5a9 --- /dev/null +++ b/src/assets/images/ic_installation_active_black.svg @@ -0,0 +1,12 @@ + + + + ic_installation_active_black + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_installation_inactive.svg b/src/assets/images/ic_installation_inactive.svg new file mode 100644 index 0000000..f87c8bf --- /dev/null +++ b/src/assets/images/ic_installation_inactive.svg @@ -0,0 +1,12 @@ + + + + ic_installation_inactive + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_location_active.svg b/src/assets/images/ic_location_active.svg new file mode 100644 index 0000000..11648f1 --- /dev/null +++ b/src/assets/images/ic_location_active.svg @@ -0,0 +1,12 @@ + + + + ic_location_active + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_location_active_black.svg b/src/assets/images/ic_location_active_black.svg new file mode 100644 index 0000000..dcb3fd8 --- /dev/null +++ b/src/assets/images/ic_location_active_black.svg @@ -0,0 +1,12 @@ + + + + ic_location_active_black + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_location_inactive.svg b/src/assets/images/ic_location_inactive.svg new file mode 100644 index 0000000..fc256d4 --- /dev/null +++ b/src/assets/images/ic_location_inactive.svg @@ -0,0 +1,12 @@ + + + + ic_location_inactive + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_more_active.svg b/src/assets/images/ic_more_active.svg new file mode 100644 index 0000000..7549261 --- /dev/null +++ b/src/assets/images/ic_more_active.svg @@ -0,0 +1,15 @@ + + + + ic_more_active + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_more_active_black.svg b/src/assets/images/ic_more_active_black.svg new file mode 100644 index 0000000..fdaacd2 --- /dev/null +++ b/src/assets/images/ic_more_active_black.svg @@ -0,0 +1,15 @@ + + + + ic_more_active_black + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_more_inactive.svg b/src/assets/images/ic_more_inactive.svg new file mode 100644 index 0000000..7a7e662 --- /dev/null +++ b/src/assets/images/ic_more_inactive.svg @@ -0,0 +1,15 @@ + + + + ic_more_inactive + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_network_active.svg b/src/assets/images/ic_network_active.svg new file mode 100644 index 0000000..1e3df19 --- /dev/null +++ b/src/assets/images/ic_network_active.svg @@ -0,0 +1,12 @@ + + + + ic_network_active + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_network_active_black.svg b/src/assets/images/ic_network_active_black.svg new file mode 100644 index 0000000..e44af97 --- /dev/null +++ b/src/assets/images/ic_network_active_black.svg @@ -0,0 +1,12 @@ + + + + ic_network_active_black + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_network_inactive.svg b/src/assets/images/ic_network_inactive.svg new file mode 100644 index 0000000..d49b6c3 --- /dev/null +++ b/src/assets/images/ic_network_inactive.svg @@ -0,0 +1,12 @@ + + + + ic_network_inactive + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_pixelperfect_active.svg b/src/assets/images/ic_pixelperfect_active.svg new file mode 100644 index 0000000..a5e8654 --- /dev/null +++ b/src/assets/images/ic_pixelperfect_active.svg @@ -0,0 +1,18 @@ + + + + ic_pixelperfect_active + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_pixelperfect_active_black.svg b/src/assets/images/ic_pixelperfect_active_black.svg new file mode 100644 index 0000000..5923564 --- /dev/null +++ b/src/assets/images/ic_pixelperfect_active_black.svg @@ -0,0 +1,18 @@ + + + + ic_pixelperfect_active_black + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_pixelperfect_inactive.svg b/src/assets/images/ic_pixelperfect_inactive.svg new file mode 100644 index 0000000..70398ab --- /dev/null +++ b/src/assets/images/ic_pixelperfect_inactive.svg @@ -0,0 +1,18 @@ + + + + ic_pixelperfect_inactive + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_rotation_active.svg b/src/assets/images/ic_rotation_active.svg new file mode 100644 index 0000000..141f060 --- /dev/null +++ b/src/assets/images/ic_rotation_active.svg @@ -0,0 +1,14 @@ + + + + ic_rotation_active + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_rotation_active_black.svg b/src/assets/images/ic_rotation_active_black.svg new file mode 100644 index 0000000..f82037b --- /dev/null +++ b/src/assets/images/ic_rotation_active_black.svg @@ -0,0 +1,14 @@ + + + + ic_rotation_active_black + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_rotation_inactive.svg b/src/assets/images/ic_rotation_inactive.svg new file mode 100644 index 0000000..f78521b --- /dev/null +++ b/src/assets/images/ic_rotation_inactive.svg @@ -0,0 +1,14 @@ + + + + ic_rotation_inactive + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_sound_active.svg b/src/assets/images/ic_sound_active.svg new file mode 100644 index 0000000..7c6be83 --- /dev/null +++ b/src/assets/images/ic_sound_active.svg @@ -0,0 +1,14 @@ + + + + ic_sound_active + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_sound_active_black.svg b/src/assets/images/ic_sound_active_black.svg new file mode 100644 index 0000000..eb53593 --- /dev/null +++ b/src/assets/images/ic_sound_active_black.svg @@ -0,0 +1,14 @@ + + + + ic_sound_active_black + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_sound_down_active.svg b/src/assets/images/ic_sound_down_active.svg new file mode 100644 index 0000000..a45012b --- /dev/null +++ b/src/assets/images/ic_sound_down_active.svg @@ -0,0 +1,15 @@ + + + + ic_sound_down_active + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_sound_down_inactive.svg b/src/assets/images/ic_sound_down_inactive.svg new file mode 100644 index 0000000..66d50cb --- /dev/null +++ b/src/assets/images/ic_sound_down_inactive.svg @@ -0,0 +1,15 @@ + + + + ic_sound_down_inactive + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_sound_inactive.svg b/src/assets/images/ic_sound_inactive.svg new file mode 100644 index 0000000..eb686c0 --- /dev/null +++ b/src/assets/images/ic_sound_inactive.svg @@ -0,0 +1,14 @@ + + + + ic_sound_inactive + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_sound_up_active.svg b/src/assets/images/ic_sound_up_active.svg new file mode 100644 index 0000000..6e70ee6 --- /dev/null +++ b/src/assets/images/ic_sound_up_active.svg @@ -0,0 +1,16 @@ + + + + ic_sound_up_active + Created with Sketch. + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_sound_up_inactive.svg b/src/assets/images/ic_sound_up_inactive.svg new file mode 100644 index 0000000..933ed07 --- /dev/null +++ b/src/assets/images/ic_sound_up_inactive.svg @@ -0,0 +1,16 @@ + + + + ic_sound_up_inactive + Created with Sketch. + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_textandcall_active.svg b/src/assets/images/ic_textandcall_active.svg new file mode 100644 index 0000000..bfb5fcc --- /dev/null +++ b/src/assets/images/ic_textandcall_active.svg @@ -0,0 +1,15 @@ + + + + ic_textandcall_active + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_textandcall_active_black.svg b/src/assets/images/ic_textandcall_active_black.svg new file mode 100644 index 0000000..cac61b4 --- /dev/null +++ b/src/assets/images/ic_textandcall_active_black.svg @@ -0,0 +1,15 @@ + + + + ic_textandcall_active_black + Created with Sketch. + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_textandcall_inactive.svg b/src/assets/images/ic_textandcall_inactive.svg new file mode 100644 index 0000000..c9b468d --- /dev/null +++ b/src/assets/images/ic_textandcall_inactive.svg @@ -0,0 +1,13 @@ + + + + ic_textandcall_inactive + Created with Sketch. + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/ic_warning.svg b/src/assets/images/ic_warning.svg new file mode 100644 index 0000000..608d77a --- /dev/null +++ b/src/assets/images/ic_warning.svg @@ -0,0 +1 @@ + diff --git a/src/assets/images/loader.svg b/src/assets/images/loader.svg new file mode 100644 index 0000000..93c3404 --- /dev/null +++ b/src/assets/images/loader.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/src/assets/images/spinner-material.svg b/src/assets/images/spinner-material.svg new file mode 100644 index 0000000..8d66bdd --- /dev/null +++ b/src/assets/images/spinner-material.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/plugins/Battery.js b/src/plugins/Battery.js new file mode 100644 index 0000000..3a4fb88 --- /dev/null +++ b/src/plugins/Battery.js @@ -0,0 +1,280 @@ +'use strict'; + +const OverlayPlugin = require('./util/OverlayPlugin'); + +/** + * Instance battery plugin. + * Provides battery level and state control. + */ +module.exports = class Battery extends OverlayPlugin { + /** + * Plugin initialization. + * + * @param {Object} instance Associated instance. + * @param {Object} i18n Translations keys for the UI. + */ + constructor(instance, i18n) { + super(instance); + + // Reference instance + this.instance = instance; + this.i18n = i18n || {}; + + // Register plugin + this.instance.battery = this; + + // Listen for initial battery charging status + this.instance.registerEventCallback('BATTERY_STATUS', (value) => { + this.updateUIBatteryChargingState(value !== 'false'); + }); + + // Display widget + this.renderToolbarButton(); + this.renderWidget(); + + // Listen for initial battery level + this.instance.registerEventCallback('BATTERY_LEVEL', this.onBatteryLevelChange.bind(this)); + + // Listen for battery messages: "state mode " + this.instance.registerEventCallback('battery', (message) => { + const values = message.split(' ').splice(-2); + + if (values.length !== 2) { + return; + } + + this.updateUIBatteryChargingState(values[0] !== 'discharging'); + this.onBatteryLevelChange(values[1]); + }); + } + + /** + * Add the button to the player toolbar. + */ + renderToolbarButton() { + const toolbars = this.instance.getChildByClass(this.instance.root, 'gm-toolbar'); + if (!toolbars) { + return; // if we don't have toolbar, we can't spawn the widget + } + + const toolbar = toolbars.children[0]; + this.toolbarBtn = document.createElement('li'); + this.toolbarBtnImage = document.createElement('div'); + this.toolbarBtnImage.className = 'gm-icon-button gm-battery-button'; + this.toolbarBtnImage.title = this.i18n.BATTERY_TITLE || 'Battery'; + this.toolbarBtn.appendChild(this.toolbarBtnImage); + this.toolbarBtn.onclick = this.toggleWidget.bind(this); + toolbar.appendChild(this.toolbarBtn); + } + + /** + * Render the widget. + */ + renderWidget() { + // Create elements + this.widget = document.createElement('div'); + this.container = document.createElement('div'); + + // Generate title + const title = document.createElement('div'); + title.className = 'gm-title'; + title.innerHTML = this.i18n.BATTERY_TITLE || 'Battery'; + this.container.appendChild(title); + + // Generate input rows + const inputs = document.createElement('div'); + inputs.className = 'gm-inputs'; + const batteryLevelLabel = this.i18n.BATTERY_CHARGE_LEVEL || 'Charge level'; + inputs.innerHTML = ''; + + // Create charge level inputs + inputs.appendChild(this.createLevelSection()); + + // Add charging label + const chargingLabel = document.createElement('label'); + chargingLabel.innerHTML = this.i18n.BATTERY_CHARGE_STATE || 'State of charge'; + inputs.appendChild(chargingLabel); + + // Add charging section + inputs.appendChild(this.createChargingSection()); + + // Setup + this.container.appendChild(inputs); + this.widget.className = 'gm-overlay gm-battery-plugin gm-hidden'; + + // Add close button + const close = document.createElement('div'); + close.onclick = this.toggleWidget.bind(this); + close.className = 'gm-close-btn'; + + this.widget.appendChild(close); + this.widget.appendChild(this.container); + + // Render into document + this.overlays.push(this.widget); + this.instance.root.appendChild(this.widget); + } + + /** + * Create and return the widget "charging" section. + * + * @return {HTMLElement} Charging section. + */ + createChargingSection() { + const chargingGroup = document.createElement('div'); + this.chargingInput = document.createElement('input'); + this.chargingStatus = document.createElement('div'); + chargingGroup.className = 'gm-charging-group'; + this.chargingInput.type = 'checkbox'; + this.chargingInput.className = 'gm-charging-checkbox'; + this.chargingInput.onchange = this.toggleChargingState.bind(this); + this.chargingInput.checked = true; + this.chargingStatus.className = 'gm-charging-status'; + this.chargingStatus.innerHTML = 'Discharging'; + chargingGroup.appendChild(this.chargingInput); + chargingGroup.appendChild(this.chargingStatus); + + return chargingGroup; + } + + /** + * Create and return the widget "level" section. + * + * @return {HTMLElement} Level section. + */ + createLevelSection() { + const chargeGroup = document.createElement('div'); + chargeGroup.className = 'gm-charge-level-group'; + + const inputGroup = document.createElement('div'); + this.chargeInput = document.createElement('input'); + const chargeInputLabel = document.createElement('span'); + chargeInputLabel.innerHTML = '%'; + this.chargeInput.className = 'gm-charge-input'; + this.chargeInput.type = 'number'; + this.chargeInput.value = 50; + this.chargeInput.max = 100; + this.chargeInput.min = 0; + this.chargeInput.step = 1; + this.chargeInput.oninput = this.onBatteryLevelChangeEvent.bind(this); + inputGroup.appendChild(this.chargeInput); + inputGroup.appendChild(chargeInputLabel); + chargeGroup.appendChild(inputGroup); + + const sliderGroup = document.createElement('div'); + this.chargeSlider = document.createElement('input'); + this.chargeSlider.className = 'gm-charge-slider'; + this.chargeSlider.type = 'range'; + this.chargeSlider.orient = 'vertical'; + this.chargeSlider.max = 100; + this.chargeSlider.min = 0; + this.chargeSlider.step = 1; + this.chargeSlider.value = 50; + this.chargeSlider.onchange = this.onBatteryLevelChangeEvent.bind(this); + sliderGroup.appendChild(this.chargeSlider); + chargeGroup.appendChild(sliderGroup); + + const chargeImageGroup = document.createElement('div'); + this.chargeImage = document.createElement('div'); + this.chargeImageOverlay = document.createElement('div'); + this.chargeImage.className = 'gm-charge-image'; + this.chargeImageOverlay.className = 'gm-charge-image-overlay'; + this.chargeImageOverlay.style.cssText = 'height: ' + 40 + '%;'; + chargeImageGroup.appendChild(this.chargeImage); + this.chargeImage.appendChild(this.chargeImageOverlay); + chargeGroup.appendChild(chargeImageGroup); + + return chargeGroup; + } + + /** + * Display or hide the widget. + */ + toggleWidget() { + // Notify other callers + if (this.widget.classList.contains('gm-hidden')) { + this.instance.emit('close-overlays'); + this.instance.emit('keyboard-disable'); + } else { + this.instance.emit('keyboard-enable'); + } + + // Toggle display + this.widget.classList.toggle('gm-hidden'); + this.toolbarBtnImage.classList.toggle('gm-active'); + } + + /** + * Toggle Instance charging status between 'charging' and 'discharging'; + */ + toggleChargingState() { + this.chargingStatus.classList.toggle('charging'); + + const chargingLabel = this.i18n.BATTERY_CHARGING || 'Charging'; + const dischargingLabel = this.i18n.BATTERY_DISCHARGING || 'Discharging'; + + this.chargingStatus.innerHTML = this.chargingInput.checked ? chargingLabel : dischargingLabel; + this.sendDataToInstance(); + } + + /** + * Update widget charging state UI. + * + * @param {boolean} charging Whether or not the battery is charging. + */ + updateUIBatteryChargingState(charging) { + this.chargingInput.checked = charging; + this.chargingStatus.classList[charging ? 'add' : 'remove']('charging'); + + const chargingLabel = this.i18n.BATTERY_CHARGING || 'Charging'; + const dischargingLabel = this.i18n.BATTERY_DISCHARGING || 'Discharging'; + + this.chargingStatus.innerHTML = charging ? chargingLabel : dischargingLabel; + } + + /** + * Handle battery level change events (slider & text input). + * + * @param {Event} event Event. + */ + onBatteryLevelChangeEvent(event) { + const value = Number(event.target.value); + if (this.onBatteryLevelChange(value)) { + this.sendDataToInstance(); + } + } + + /** + * Synchronize widget UI. + * + * @param {number} value Battery level. + * @return {boolean} Whether or not battery level has been applied. + */ + onBatteryLevelChange(value) { + value = Number(value); + if (Number.isNaN(value)) { + return false; + } + + value = Math.min(Math.max(0, value), 100); + this.chargeSlider.value = value; + this.chargeInput.value = value; + this.chargeImageOverlay.style.cssText = 'height: ' + (value * 0.7 + 4) + '%;'; + return true; + } + + /** + * Send information to instance. + */ + sendDataToInstance() { + const level = Number(this.chargeInput.value); + const charging = this.chargingInput.checked ? 'charging' : 'discharging'; + const json = { + channel: 'battery', messages: [ + 'set state level ' + level, + 'set state status ' + charging, + ], + }; + this.instance.sendEvent(json); + } +}; diff --git a/src/plugins/ButtonsEvents.js b/src/plugins/ButtonsEvents.js new file mode 100644 index 0000000..b06b58a --- /dev/null +++ b/src/plugins/ButtonsEvents.js @@ -0,0 +1,230 @@ +'use strict'; + +const META_KEYCODE = '0x01000022'; +const ENTER_KEYCODE = '0x01000005'; +const VOLUME_DOWN_KEYCODE = '0x01000070'; +const VOLUME_UP_KEYCODE = '0x01000072'; +const RECENT_APP_KEYCODE = '0x010000be'; +const HOME_KEYCODE = '0x01000010'; +const BACK_KEYCODE = '0x01000061'; +const POWER_KEYCODE = '0x0100010b'; +const ROTATE_KEYCODE = 'gm-rotation'; + +/** + * Instance physical buttons plugin. + * Provides physical buttons (power, volume, ...) control. + */ +module.exports = class ButtonsEvents { + /** + * Plugin initialization. + * + * @param {Object} instance Associated instance. + * @param {Object} i18n Translations keys for the UI. + * @param {Object} translateHomeKey Translate HOME key press for the instance. + */ + constructor(instance, i18n, translateHomeKey) { + // Reference instance + this.instance = instance; + this.translateHomeKey = translateHomeKey; + + // Register plugin + this.instance.buttonsEvents = this; + + if (this.instance.options.rotation) { + this.renderToolbarButton(ROTATE_KEYCODE, 'gm-rotate', i18n.BUTTONS_ROTATE || 'Rotate', false); + } + + if (this.instance.options.volume) { + this.renderToolbarButton( + VOLUME_DOWN_KEYCODE, 'gm-sound-down', i18n.BUTTONS_SOUND_DOWN || 'Sound down', false + ); + this.renderToolbarButton(VOLUME_UP_KEYCODE, 'gm-sound-up', i18n.BUTTONS_SOUND_UP || 'Sound up', false); + } + + if (this.instance.options.navbar) { + this.renderToolbarButton( + RECENT_APP_KEYCODE, 'gm-recent', i18n.BUTTONS_RECENT_APPS || 'Recent applications', true + ); + this.renderToolbarButton(HOME_KEYCODE, 'gm-home', i18n.BUTTONS_HOME || 'Home', true); + this.renderToolbarButton(BACK_KEYCODE, 'gm-back', i18n.BUTTONS_BACK || 'Back', true); + } + + if (this.instance.options.power) { + this.renderToolbarButton(POWER_KEYCODE, 'gm-power', i18n.BUTTONS_POWER || 'Power', true); + } + + const buttons = document.getElementsByClassName('gm-icon-button'); + for (let i = 0; i < buttons.length; i++) { + const button = buttons[i]; + button.onmousedown = this.mouseButtonPressEvent.bind(this); + button.onmouseup = this.mouseButtonReleaseEvent.bind(this); + } + } + + /** + * Called on keyboard keypress event. + * Relay keypress event to the instance. + * + * @param {string} key Pressed key unicode reference number. + * @param {string} text Pressed key character. + */ + keyPressEvent(key, text) { + const json = {type: 'KEYBOARD_PRESS', keychar: text, keycode: key}; + this.instance.sendEvent(json); + } + + /** + * Called on keyboard keyrelease event. + * Relay keyrelease event to the instance. + * + * @param {string} key Released key unicode reference number. + * @param {string} text Released key character. + */ + keyReleaseEvent(key, text) { + const json = {type: 'KEYBOARD_RELEASE', keychar: text, keycode: key}; + this.instance.sendEvent(json); + } + + /** + * Called on mouse down event. + * Relay event to the instance. + * + * @param {Event} event Associated JS event + */ + mouseButtonPressEvent(event) { + const id = event.target.classList[1]; + if (!id) { + return; + } + + if (id === HOME_KEYCODE && this.translateHomeKey) { // home is meta + enter + this.keyPressEvent(parseInt(META_KEYCODE), ''); + this.keyPressEvent(parseInt(ENTER_KEYCODE), ''); + } else if (id.substring(0, 2) === '0x') { // else if it is a raw key we send it + const key = parseInt(id, 16); + this.keyPressEvent(key, '0\n'); + } + } + + /** + * Called on mouse up event. + * Relay event to the instance. + * + * @param {Event} event Associated JS event + */ + mouseButtonReleaseEvent(event) { + const id = event.target.classList[1]; + if (!id) { + return; + } + + if (id === HOME_KEYCODE && this.translateHomeKey) { // "home" is "meta + enter" on PaaS, "move_home" on SaaS + this.keyReleaseEvent(parseInt(ENTER_KEYCODE), ''); + this.keyReleaseEvent(parseInt(META_KEYCODE), ''); + } else if (id === ROTATE_KEYCODE) { // rotate is a custom command + const json = {type: 'ROTATE'}; + this.instance.sendEvent(json); + } else if (id.substring(0, 2) === '0x') { // else if it is a raw key we send it + const key = parseInt(id, 16); + this.keyReleaseEvent(key, '0\n'); + } + } + + /** + * Retrieve a button from its class name. + * + * @param {string} className Button class name. + * @return {Object} Button state. + */ + getButtonState(className) { + const image = this.instance.getChildByClass(this.instance.root, className); + const button = image.parentNode; + + return { + image: { + className: image.className, + }, + button: { + className: button.className, + onclick: button.onclick, + } + }; + } + + /** + * Retrieve a button state identified by its class name. + * + * @param {string} className Button class name. + * @param {Object} state Button state + */ + setButtonState(className, state) { + const image = this.instance.getChildByClass(this.instance.root, className); + const button = image.parentNode; + + image.className = state.image.className; + button.className = state.button.className; + button.onclick = state.button.onclick; + } + + /** + * Disable instance rotation. + */ + disableRotation() { + if (!this.instance.getChildByClass(this.instance.root, 'gm-rotate')) { + return; // if we don't have rotation, we can't disable it + } + + if (!this.savedRotationState) { + this.savedRotationState = this.getButtonState('gm-rotate'); + } + + const rotationImage = this.instance.getChildByClass(this.instance.root, 'gm-rotate'); + const rotationButton = rotationImage.parentNode; + rotationButton.className += ' gm-disabled-widget-pop-up'; + rotationImage.className += ' gm-disabled-widget-icon'; + rotationButton.onclick = null; + } + + /** + * Enable instance rotation. + */ + enableRotation() { + if (!this.instance.getChildByClass(this.instance.root, 'gm-rotate')) { + return; // if we don't have rotation, we can't disable it + } + + if (this.savedRotationState) { + this.setButtonState('gm-rotate', this.savedRotationState); + this.savedRotationState = null; + } + } + + /** + * Add a device button to the player toolbar. + * + * @param {string} androidKeycode Button keycode. + * @param {string} htmlClass Button CSS class. + * @param {string} htmlTitle Button title. + * @param {boolean} append Set to true to insert the button at the end. + */ + renderToolbarButton(androidKeycode, htmlClass, htmlTitle, append) { + const toolbars = this.instance.getChildByClass(this.instance.root, 'gm-toolbar'); + if (!toolbars) { + return; // if we don't have toolbar, we can't spawn the widget + } + + const toolbar = toolbars.children[0]; + const button = document.createElement('li'); + const image = document.createElement('div'); + image.classList.add('gm-icon-button'); + image.classList.add(androidKeycode); + image.classList.add(htmlClass); + image.title = htmlTitle; + button.appendChild(image); + if (append) { + toolbar.appendChild(button); + } else { + toolbar.insertBefore(button, toolbar.firstChild); + } + } +}; diff --git a/src/plugins/Camera.js b/src/plugins/Camera.js new file mode 100644 index 0000000..ad77e4c --- /dev/null +++ b/src/plugins/Camera.js @@ -0,0 +1,127 @@ +'use strict'; + +const adapterjs = require('webrtc-adapter'); +const OverlayPlugin = require('./util/OverlayPlugin'); + +const log = require('loglevel'); +log.setDefaultLevel('debug'); + +/** + * Instance camera plugin. + * Provides client webcam and camera control. + */ +module.exports = class Camera extends OverlayPlugin { + /** + * Plugin initialization. + * + * @param {Object} instance Associated instance. + * @param {Object} i18n Translations keys for the UI. + */ + constructor(instance, i18n) { + super(instance); + + // Reference instance + this.instance = instance; + this.i18n = i18n || {}; + + // Register plugin + this.instance.camera = this; + + this.streaming = false; + + // Display widget + this.renderToolbarButton(); + } + + /** + * Add the button to the player toolbar. + */ + renderToolbarButton() { + const toolbars = this.instance.getChildByClass(this.instance.root, 'gm-toolbar'); + if (!toolbars) { + return; // if we don't have toolbar, we can't spawn the widget + } + + const toolbar = toolbars.children[0]; + this.toolbarBtn = document.createElement('li'); + this.toolbarBtnImage = document.createElement('div'); + this.toolbarBtnImage.className = 'gm-icon-button gm-camera-button'; + this.toolbarBtnImage.title = this.i18n.CAMERA_TITLE || 'Use webcam as camera'; + this.toolbarBtn.appendChild(this.toolbarBtnImage); + toolbar.appendChild(this.toolbarBtn); + + // if we are using safari, we disable camera since it sends its stream on h264 which is not currently supported + if (adapterjs.default.browserDetails.browser === 'safari') { + this.toolbarBtn.className += ' gm-disabled-widget-pop-up'; + this.toolbarBtnImage.className += ' gm-disabled-widget-icon'; + } else { + this.toolbarBtn.onclick = this.toggleStreaming.bind(this); + } + } + + /** + * Toggle local video forward forwarding. + * Redirect the client webcam video stream to the instance. + */ + toggleStreaming() { + if (!this.streaming) { + this.startStreaming(); + } else { + this.stopStreaming(); + } + } + + /** + * Initialize and start client webcam video stream. + */ + startStreaming() { + if (!navigator.mediaDevices) { + return; + } + + navigator.mediaDevices.getUserMedia({ + audio: this.instance.options.microphone, + video: { + width:1280, + height: 720, + }, + }) + .catch((err) => { + this.onVideoStreamError(err); + }) + .then((mediaStream) => { + log.debug('Client video stream ready'); + this.streaming = true; + this.localStream = mediaStream; + this.instance.addLocalStream(mediaStream); + }); + } + + /** + * Client video stream error handler. + * + * @param {Error} error Camera stream error. + */ + onVideoStreamError(error) { + log.warn('Can\'t start client video stream', error); + } + + /** + * Stop client webcam video stream. + */ + stopStreaming() { + log.debug('removed local stream'); + this.instance.removeLocalStream(this.localStream); + this.localStream = null; + this.streaming = false; + } + + /** + * Get client webcam video stream. + * + * @return {MediaStream} Client video stream + */ + getClientVideoStream() { + return this.localStream; + } +}; diff --git a/src/plugins/Clipboard.js b/src/plugins/Clipboard.js new file mode 100644 index 0000000..78bd169 --- /dev/null +++ b/src/plugins/Clipboard.js @@ -0,0 +1,180 @@ +'use strict'; + +const OverlayPlugin = require('./util/OverlayPlugin'); + +const log = require('loglevel'); +log.setDefaultLevel('debug'); + +/** + * Instance clipboard plugin. + * Provides clipboard data exchange capability between client and instance. + */ +module.exports = class Clipboard extends OverlayPlugin { + /** + * Plugin initialization. + * + * @param {Object} instance Associated instance. + * @param {Object} i18n Translations keys for the UI. + */ + constructor(instance, i18n) { + super(instance); + + // Reference instance + this.instance = instance; + this.i18n = i18n || {}; + + // Register plugin + this.instance.clipboard = this; + + // clipboard text + this.clipboard = ''; + + // Display widget + this.renderToolbarButton(); + this.renderWidget(); + + // Listen for framework messages: "clipboard " + this.instance.registerEventCallback('framework', (message) => { + const values = message.split(' '); + if (values.length !== 3 || values[0] !== 'clipboard') { + return; + } + + try { + this.clipboard = decodeURIComponent(escape(window.atob(values[2]))); + } catch (error) { + log.warn('Malformed clipboard content'); + } + }); + + // Listen for initial clipboard status + this.instance.registerEventCallback('CLIPBOARD', (text) => { + this.clipboard = text; + }); + } + + /** + * Add the button to the player toolbar. + */ + renderToolbarButton() { + const toolbars = this.instance.getChildByClass(this.instance.root, 'gm-toolbar'); + if (!toolbars) { + return; // if we don't have toolbar, we can't spawn the widget + } + + const toolbar = toolbars.children[0]; + this.toolbarBtn = document.createElement('li'); + this.toolbarBtnImage = document.createElement('div'); + this.toolbarBtnImage.className = 'gm-icon-button gm-clipboard-button'; + this.toolbarBtnImage.title = this.i18n.CLIPBOARD_TITLE || 'Clipboard'; + this.toolbarBtn.appendChild(this.toolbarBtnImage); + this.toolbarBtn.onclick = this.toggleWidget.bind(this); + toolbar.appendChild(this.toolbarBtn); + } + + /** + * Render the widget. + */ + renderWidget() { + // Create elements + this.widget = document.createElement('div'); + this.container = document.createElement('div'); + + // Generate title + const title = document.createElement('div'); + title.className = 'gm-title'; + title.innerHTML = this.i18n.CLIPBOARD_TITLE || 'Clipboard'; + this.container.appendChild(title); + + this.clipboardInput = document.createElement('textarea'); + this.clipboardInput.className = 'gm-clipboard-input'; + + this.copiedText = document.createElement('div'); + this.copiedText.innerHTML = this.i18n.CLIPBOARD_COPIED || 'Copied to local clipboard'; + this.copiedText.classList.add('gm-text-copied'); + this.copiedText.classList.add('gm-invisible'); + this.copiedText.classList.add('gm-hidden'); + + // Setup + this.container.appendChild(this.clipboardInput); + this.container.appendChild(this.copiedText); + this.widget.className = 'gm-overlay gm-clipboard-plugin gm-hidden'; + + // Add close button + const close = document.createElement('div'); + close.className = 'gm-close-btn'; + close.onclick = this.toggleWidget.bind(this); + + this.widget.appendChild(close); + this.widget.appendChild(this.container); + + this.widget.onclose = () => { + this.clipboard = this.clipboardInput.value; + this.sendDataToInstance(); + }; + + // Render into document + this.overlays.push(this.widget); + this.instance.root.appendChild(this.widget); + } + + /** + * Display or hide the widget. + */ + toggleWidget() { + // Notify other callers + if (this.widget.classList.contains('gm-hidden')) { + this.instance.emit('close-overlays'); + this.instance.emit('keyboard-disable'); + this.clipboardInput.value = this.clipboard; + if (this.clipboard !== '') { + setTimeout(this.copyInstanceClipboardToClient, 100, this.clipboardInput, this.copiedText); + } + } else { + this.instance.emit('keyboard-enable'); + this.widget.onclose(); + } + + // Toggle display + this.widget.classList.toggle('gm-hidden'); + this.toolbarBtnImage.classList.toggle('gm-active'); + } + + /** + * Copy the instance clipboard (reflected to the text input field) into the client clipboard. + * + * @param {HTMLElement} clipboardInput Clipboard value (text input). + * @param {HTMLElement} clipboardCopyIndicator Clipboard copy indicator. + */ + copyInstanceClipboardToClient(clipboardInput, clipboardCopyIndicator) { + try { + navigator.clipboard.writeText(this.clipboardInput.value); + } catch (error) { + // Old, deprecated fallback + clipboardInput.focus(); + clipboardInput.select(); + document.execCommand('copy'); + } + + clipboardCopyIndicator.classList.remove('gm-invisible'); + clipboardCopyIndicator.classList.remove('gm-hidden'); + setTimeout(() => { + clipboardCopyIndicator.classList.add('gm-invisible'); + setTimeout(() => { + clipboardCopyIndicator.classList.add('gm-hidden'); + }, 500); + }, 2000); + } + + /** + * Send information to instance. + */ + sendDataToInstance() { + const json = { + channel: 'framework', messages: [ + 'set_device_clipboard ' + window.btoa(unescape(encodeURIComponent(this.clipboard))), + ], + }; + this.instance.sendEvent(json); + } +}; diff --git a/src/plugins/CoordinateUtils.js b/src/plugins/CoordinateUtils.js new file mode 100644 index 0000000..5731157 --- /dev/null +++ b/src/plugins/CoordinateUtils.js @@ -0,0 +1,165 @@ +'use strict'; + +/** + * Screen coordinates utility plugin. + * Provides utility functions related to mouse inputs & the instance video stream. + * Used by MouseEvents and MultiTouchEvents plugins. + */ +module.exports = class CoordinateUtils { + /** + * Plugin initialization. + * + * @param {Object} instance Associated instance. + */ + constructor(instance) { + // Reference instance + this.instance = instance; + + // Register plugin + this.instance.coordinateUtils = this; + + // Virtual device video stream + this.video = this.instance.video; + } + + /** + * Keep the video stream reference in sync. + */ + setVideoElement() { + this.video = this.instance.video; + } + + /** + * Determine the position of the instance offset borders. + * + * @return {boolean} True if borders are on on the left and right side, else if they are on top and bottom. + */ + hasLeftAndRightBorders() { + return this.video.offsetWidth / this.video.offsetHeight > this.video.videoWidth / this.video.videoHeight; + } + + /** + * Determine if the instance and the player video share the same orientation. + * + * @return {boolean} True if the instance and the player video are in the same orientation. + */ + hasSameOrientation() { + return this.video.videoWidth / this.video.videoHeight > 1 && + this.video.offsetWidth / this.video.offsetHeight > 1 + || + this.video.videoWidth / this.video.videoHeight < 1 && + this.video.offsetWidth / this.video.offsetHeight < 1; + } + + /** + * Get cumulative offset between a givem element and the top left corner of the web page. + * + * @param {HTMLElement} element DOM element to get the position from. + * @return {Object} Offset (top and left). + */ + getCumulativeOffset(element) { + let top = 0; + let left = 0; + do { + top += element.offsetTop || 0; + left += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + + return { + top: top, + left: left, + }; + } + + /** + * Get the relative (cumulative, offset deduced) x coordinate from an event (touch or mouse). + * + * @param {Event} event Raw mouse/touch event. + * @return {number} Relative x coordinate. + */ + getRawXCoordinateFromEvent(event) { + if (typeof event.pageX !== 'undefined') { + if (typeof event.offsetX !== 'undefined') { + return event.offsetX; + } + return event.pageX - this.getCumulativeOffset(this.video).left; + } + return event.clientX - this.getCumulativeOffset(this.video).left; + } + + /** + * Get the relative (cumulative, offset deduced) y coordinate from an event (touch or mouse). + * + * @param {Event} event Raw mouse/touch event. + * @return {number} Relative y coordinate. + */ + getRawYCoordinateFromEvent(event) { + if (typeof event.pageY !== 'undefined') { + if (typeof event.offsetY !== 'undefined') { + return event.offsetY; + } + return event.pageY - this.getCumulativeOffset(this.video).top; + } + return event.clientY - this.getCumulativeOffset(this.video).top; + } + + /** + * Get the final emulated x coordinate. Video ratio & orientation taken into account. + * + * @param {Event} event Raw mouse/touch event. + * @return {number} Relative x coordinate. + */ + getXCoordinate(event) { + this.instance.root.focus(); // not on the Y function because we need to focus element only once + this.setVideoElement(); + const x = this.getRawXCoordinateFromEvent(event); + let videoRealSizeX, ratio; + if (this.hasSameOrientation()) { + if (this.hasLeftAndRightBorders()) { + videoRealSizeX = this.video.videoWidth / this.video.videoHeight * this.video.offsetHeight; + const xRatio = this.video.videoWidth / videoRealSizeX; + const blackBorderSize = (this.video.offsetWidth - videoRealSizeX) / 2; + return (x - blackBorderSize) * xRatio; + } + return this.video.videoWidth / this.video.offsetWidth * x; + } + if (this.hasLeftAndRightBorders()) { + videoRealSizeX = this.video.videoWidth / this.video.videoHeight * this.video.offsetHeight; + ratio = this.video.videoWidth / videoRealSizeX; + return (x - (this.video.offsetWidth - videoRealSizeX) / 2) * ratio; + } + const videoRealSizeY = this.video.videoHeight / this.video.videoWidth * this.video.offsetWidth; + ratio = this.video.videoHeight / videoRealSizeY; + return x * ratio; + } + + /** + * Get the final emulated y coordinate. Video ratio & orientation taken into account. + * + * @param {Event} event Raw mouse/touch event. + * @return {number} Relative y coordinate. + */ + getYCoordinate(event) { + this.setVideoElement(); + const y = this.getRawYCoordinateFromEvent(event); + let videoRealSizeX, videoRealSizeY, ratio; + if (this.hasSameOrientation()) { + if (this.hasLeftAndRightBorders()) { + return this.video.videoHeight / this.video.offsetHeight * y; + } + videoRealSizeY = this.video.videoHeight / this.video.videoWidth * this.video.offsetWidth; + const yRatio = this.video.videoHeight / videoRealSizeY; + const blackBorderTopSize = (this.video.offsetHeight - videoRealSizeY) / 2; + return (y - blackBorderTopSize) * yRatio; + } + if (this.hasLeftAndRightBorders()) { + videoRealSizeX = this.video.videoWidth / this.video.videoHeight * this.video.offsetHeight; + ratio = this.video.videoWidth / videoRealSizeX; + return y * ratio; + } + videoRealSizeY = this.video.videoHeight / this.video.videoWidth * this.video.offsetWidth; + ratio = this.video.videoHeight / videoRealSizeY; + return (y - (this.video.offsetHeight - videoRealSizeY) / 2) * ratio; + } +}; diff --git a/src/plugins/FileUpload.js b/src/plugins/FileUpload.js new file mode 100644 index 0000000..b265dbd --- /dev/null +++ b/src/plugins/FileUpload.js @@ -0,0 +1,777 @@ +'use strict'; + +const OverlayPlugin = require('./util/OverlayPlugin'); + +const LEFT = 0; +const RIGHT = 1; + +const CIRC = Math.PI * 2; +const QUART = Math.PI / 2; + +/** + * Instance file upload plugin. + * Provides file upload support and Open GApps installation control. + */ +module.exports = class FileUpload extends OverlayPlugin { + /** + * Plugin initialization. + * + * @param {Object} instance Associated instance. + * @param {Object} i18n Translations keys for the UI. + */ + constructor(instance, i18n) { + super(instance); + + // Reference instance + this.instance = instance; + this.i18n = i18n || {}; + + // Register plugin + this.instance.fileUpload = this; + + this.root = this.instance.videoWrapper; + this.stepper = {}; + this.currentStep = 'homeScreen'; + this.isUploading = false; + this.hasError = false; + this.flashing = false; + this.canvasContext = null; + this.opengappsInstalled = false; + this.capabilityAvailable = false; + + if (window.Worker) { + let fileUploaderWorker = require('../worker/FileUploaderWorker'); + fileUploaderWorker = fileUploaderWorker.toString() + .match(/^\s*function\s*\(\s*\)\s*\{(([\s\S](?!\}$))*[\s\S])/)[1]; + const src = new Blob([fileUploaderWorker], {type: 'application/javascript'}); + this.loaderWorker = new Worker(URL.createObjectURL(src)); + this.loaderWorker.onmessage = (event) => { + const msg = event.data; + switch (msg.code) { + case 'SUCCESS': + this.onUploadSuccess(); + break; + case 'FAIL': + this.onUploadFailure(); + break; + case 'PROGRESS': + this.setUploadProgress(msg.value); + break; + default: + break; + } + }; + } + + this.root.ondragenter = (event) => { + event.stopPropagation(); + event.preventDefault(); + }; + + this.root.ondragover = (event) => { + event.stopPropagation(); + event.preventDefault(); + }; + + this.root.ondragleave = (event) => { + event.stopPropagation(); + event.preventDefault(); + }; + + this.root.ondrop = (event) => { + event.stopPropagation(); + event.preventDefault(); + if (!this.isUploading) { + this.upload(event.dataTransfer.files); + } + }; + + // create stepper + this.createStepper(); + + // Render components + this.renderToolbarButton(); + this.renderWidget(); + + // Listen for events + this.instance.registerEventCallback('SYSTEM_PATCHER_STATUS', this.onSystemPatcherStatusEvent.bind(this)); + this.instance.registerEventCallback( + 'SYSTEM_PATCHER_LAST_RESULT', this.onSystemPatcherLastResultEvent.bind(this) + ); + + /* + * Listen for systempatcher messages: "status " + * or "last_result _error " + */ + this.instance.registerEventCallback('systempatcher', (message) => { + const split = message.split(/ (.+)/); + if (split[0] === 'status') { + this.onSystemPatcherStatusEvent(split[1]); + } else if (split[0] === 'last_result') { + this.onSystemPatcherLastResultEvent(split[1]); + } + }); + } + + /** + * Add the button to the player toolbar. + */ + renderToolbarButton() { + const toolbars = this.instance.getChildByClass(this.instance.root, 'gm-toolbar'); + if (!toolbars) { + return; // if we don't have toolbar, we can't spawn the widget + } + + const toolbar = toolbars.children[0]; + const button = document.createElement('li'); + this.toolbarBtnImage = document.createElement('div'); + this.toolbarBtnImage.className = 'gm-icon-button gm-uploader-button'; + this.toolbarBtnImage.title = this.i18n.UPLOADER_TITLE || 'File upload'; + button.appendChild(this.toolbarBtnImage); + button.onclick = this.toggleWidget.bind(this); + toolbar.appendChild(button); + } + + /** + * Render the widget. + */ + renderWidget() { + // Create elements + this.widget = document.createElement('div'); + this.container = document.createElement('div'); + + // Generate title + this.title = document.createElement('div'); + this.title.className = 'gm-upload-title'; + this.container.appendChild(this.title); + + // Generate input rows + this.inputs = document.createElement('div'); + this.inputs.className = 'gm-uploader-content'; + + // Setup + this.container.appendChild(this.inputs); + this.widget.className = 'gm-overlay gm-uploader-plugin gm-hidden'; + + // Add close button + const close = document.createElement('div'); + close.className = 'gm-close-btn'; + close.onclick = this.toggleWidget.bind(this); + this.widget.appendChild(close); + this.widget.appendChild(this.container); + + // Render into document + this.overlays.push(this.widget); + this.instance.root.appendChild(this.widget); + } + + /** + * Display or hide the widget. + */ + toggleWidget() { + // Notify other callers + if (this.widget.classList.contains('gm-hidden')) { + this.instance.emit('close-overlays'); + this.instance.emit('keyboard-disable'); + this.displayStep(this.currentStep); + // Force refresh upload screen content. Otherwise, installing status may not appear. + if (this.currentStep === 'uploadScreen') { + const json = { + channel: 'systempatcher', messages: [ + 'notify status' + ] + }; + this.instance.sendEvent(json); + } + } else { + // Only reset step to homeScreen if we are in success or error step + if (this.currentStep === 'successScreen' || this.currentStep === 'errorScreen') { + this.currentStep = 'homeScreen'; + } + this.instance.emit('keyboard-enable'); + } + + // Toggle display + this.widget.classList.toggle('gm-hidden'); + this.toolbarBtnImage.classList.toggle('gm-active'); + } + + /** + * Start uploading file(s) to the instance. + * + * @param {DataTransferItemList} files Files to upload. + */ + upload(files) { + if (files.length <= 0) { + return; + } + + this.createUploadProgressCanvas(); + this.setUploadProgress(0); + const msg = {type: 'upload', file: files[0]}; + this.loaderWorker.postMessage(msg); + this.isUploading = true; + this.hasError = false; + } + + /** + * Display a message and fade it out. + */ + onUploadSuccess() { + this.isUploading = false; + this.canvasContext.putImageData(this.canvasImageData, 0, 0); + this.canvasContext.fillText('✓', 30, 80); + this.canvasContext.stroke(); + setTimeout(() => { + this.canvasContext.putImageData(this.canvasImageData, 0, 0); + }, 750); + } + + /** + * Handle upload errors + */ + onUploadFailure() { + this.isUploading = false; + this.hasError = true; + } + + /** + * Updade upload progress in the UI. + * + * @param {number} percentage Upload progress percentage. + * @param {string} color Color to use. + */ + setUploadProgress(percentage, color) { + if (!this.hasError) { + this.drawProgress(percentage, color); + } + } + + /** + * SystemPatcher status event handler. + * Event payload can be: + * - "downloading " + * - "installing" + * - "ready opengapps" + * + * @param {string} message Event payload. + */ + onSystemPatcherStatusEvent(message) { + const textProgressPercent = document.getElementsByClassName('gm-upload-in-progress-txt-percent')[0]; + const textProgress = document.getElementsByClassName('gm-upload-in-progress-txt-progress')[0]; + const progressPercent = document.getElementsByClassName('gm-upload-in-progress-percent')[0]; + const data = message.split(' '); + + if (data[0] === 'downloading' && data.length >= 3 && textProgressPercent && + textProgress && progressPercent) { + const bytesDone = parseInt(data[1]); + const totalBytes = parseInt(data[2]); + if (totalBytes === 0 || Number.isNaN(totalBytes)) { + return; + } + + const percent = Math.round(100 * bytesDone / totalBytes); + textProgressPercent.innerHTML = percent + '%'; + progressPercent.style.width = percent + '%'; + + // Convert in Mb + const Mb = 1024 * 1024; + const mbDone = Math.round(10 * bytesDone / Mb) / 10; + const totalMb = Math.round(10 * totalBytes / Mb) / 10; + const msg = 'Downloading '+ mbDone +' Mb/' + totalMb +' Mb'; + textProgress.innerHTML = msg; + } else if (data[0] === 'installing' && textProgress) { + textProgress.innerHTML = this.i18n.UPLOADER_INSTALLING || 'Installing...'; + } else if (data[0] === 'ready' && data.length >= 2) { + if (data[1].indexOf('opengapps') !== -1) { + this.updateOpenGAppsStatus(true); + } + + if (!this.flashing) { + return; + } + + const json = { + channel: 'systempatcher', messages: [ + 'notify last_result' + ] + }; + this.instance.sendEvent(json); + } + } + + /** + * SystemPatcher lastresult event handler. + * + * @param {string} message Event payload. + */ + onSystemPatcherLastResultEvent(message) { + switch (message) { + case 'success': + this.displayStep('successScreen'); + // On flashing success, force display success screen + if (this.flashing && this.widget.classList.contains('gm-hidden')) { + this.toggleWidget(); + } + this.flashing = false; + break; + case 'unavailable': + case 'network_error': + case 'corrupted_archive': + case 'install_error': + this.displayStep('errorScreen'); + // On flashing error, force display errorscreen + if (this.flashing && this.widget.classList.contains('gm-hidden')) { + this.toggleWidget(); + } + this.flashing = false; + break; + default: + break; + } + } + + /** + * Create a canvas to provide an area to display upload progress. + */ + createUploadProgressCanvas() { + if (this.canvasContext) { + return; + } + + const canvas = document.createElement('canvas'); + canvas.classList.add('gm-upload-progress'); + canvas.width = 120; + canvas.height = 120; + this.instance.wrapper.insertBefore(canvas, this.instance.wrapper.firstChild); + this.canvasContext = canvas.getContext('2d'); + this.canvasImageData = null; + + this.canvasContext.beginPath(); + this.canvasContext.strokeStyle = '#E6195E'; + this.canvasContext.fillStyle = '#E6195E'; + this.canvasContext.lineCap = 'square'; + this.canvasContext.font = 'bold 60px Arial'; + this.canvasContext.lineWidth = 10.0; + this.canvasContext.closePath(); + this.canvasContext.fill(); + + this.canvasImageData = this.canvasContext.getImageData(0, 0, 120, 120); + } + + /** + * Draw upload progress (0 = nothing displayed; 1 = full circle). + * + * @param {number} percentage Upload progress percentage. + * @param {string} color Color to use. + */ + drawProgress(percentage, color) { + color = typeof color !== 'undefined' ? color : '#E6195E'; + this.canvasContext.strokeStyle = color; + this.canvasContext.fillStyle = color; + this.canvasContext.putImageData(this.canvasImageData, 0, 0); + this.canvasContext.beginPath(); + this.canvasContext.arc(60, 60, 55, -QUART, CIRC * percentage - QUART, false); + percentage = Math.round(percentage * 100); + const text = percentage !== 100 ? percentage : '99'; // do not display 100 (3 digit) + this.canvasContext.fillText(text, 25, 80); + this.canvasContext.stroke(); + } + + /** + * Create the all file upload screens. + */ + createStepper() { + this.stepper.homeScreen = this.createHomeScreen.bind(this); + this.stepper.disclaimerScreen = this.createDisclaimerScreen.bind(this); + this.stepper.uploadScreen = this.createUploadScreen.bind(this); + this.stepper.successScreen = this.createSuccessStep.bind(this); + this.stepper.errorScreen = this.createErrorStep.bind(this); + } + + /** + * Display a specific file upload screen. + * + * @param {string} step Screen name. + */ + displayStep(step) { + this.currentStep = step; + // Reset main content + this.inputs.innerHTML = ''; + + // Set current step + const template = this.stepper[step](); + this.title.innerHTML = template.title; + this.inputs.appendChild(template.body); + } + + /** + * Enable or disable the file upload capability. + * + * @param {boolean} available Upload availability. + */ + setAvailability(available) { + this.capabilityAvailable = available; + } + + /** + * Create and return the "home" file upload screen. + * + * @return {Object} HTMLElement & title for this screen. + */ + createHomeScreen() { + // Main div on the home page of the Open GApps widget + const homeContent = document.createElement('div'); + const headerHomeContent = document.createElement('div'); + headerHomeContent.className = 'gm-upload-main'; + + // Define image on home view of Open GApps popup + headerHomeContent.appendChild(this.createIconDiv('gm-upload-main-img')); + + // Define small text zone on home view + headerHomeContent.appendChild(this.createTextDiv( + 'gm-upload-main-txt', + '

You can install Open GApps, or upload a file: APK files will be installed, ' + + 'flashable archives will be flashed, and other files types will be pushed ' + + 'to the /sdcard/download folder on the device.

' + )); + + // Slit in header and bottom part + homeContent.appendChild(headerHomeContent); + + this.uploader = document.createElement('input'); + this.uploader.className = 'gm-uploader-file'; + this.uploader.type = 'file'; + this.uploader.setAttribute('gm-hidden', ''); + homeContent.appendChild(this.uploader); + + this.uploader.onchange = () => { + if (!this.isUploading) { + this.toggleWidget(); + this.upload(this.uploader.files); + } + }; + + // Define 2 buttons at widget bottom + const bottomButtonsContainer = document.createElement('div'); + bottomButtonsContainer.className = 'gm-upload-main-bottom-buttons'; + + const buttons = this.createButtonsGroup('Install Open GApps', (event) => { + event.preventDefault(); + + if (this.opengappsInstalled === false && this.capabilityAvailable) { + this.displayStep('disclaimerScreen'); + } + }, 'Browse', (event) => { + event.preventDefault(); + this.uploader.click(); + }); + + this.installButton = buttons[LEFT]; + this.updateOpenGAppsStatus(this.opengappsInstalled); + + bottomButtonsContainer.appendChild(buttons[LEFT]); + bottomButtonsContainer.appendChild(buttons[RIGHT]); + + // Add buttons and all home content view for this widget in the DOM + homeContent.appendChild(bottomButtonsContainer); + + return { + body: homeContent, + title: this.i18n.UPLOADER_HOME_TITLE || 'Upload file to the virtual device', + }; + } + + /** + * Update the "home" file upload screen. + * + * @param {boolean} installed Whether or not OpenGApps are installed on the instance. + */ + updateOpenGAppsStatus(installed) { + this.opengappsInstalled = installed; + + if (!this.installButton) { + return; + } + + if (!this.capabilityAvailable) { + this.installButton.className = + 'gm-upload-main-bottom-buttons-left gm-dont-close gm-uploader-install-opengapps ' + + 'gm-upload-main-bottom-buttons-disabled'; + this.installButton.innerHTML = 'Install Open GApps'; + this.installButton.title = 'Open GApps are not available for this virtual device'; + return; + } + + if (installed) { + this.installButton.className = + 'gm-upload-main-bottom-buttons-left gm-dont-close gm-uploader-install-opengapps ' + + 'gm-upload-main-bottom-buttons-disabled'; + this.installButton.innerHTML = 'Open GApps installed'; + this.installButton.title = 'Open GApps are already installed'; + } else { + this.installButton.className = + 'gm-upload-main-bottom-buttons-left gm-dont-close gm-uploader-install-opengapps'; + + this.installButton.innerHTML = 'Install Open GApps'; + this.installButton.title = 'Install Open GApps'; + } + } + + /** + * Create and return the "disclaimer" file upload screen. + * + * @return {Object} HTMLElement & title for this screen. + */ + createDisclaimerScreen() { + // Main div on the home page of the Opengapps widget + const homeContent = document.createElement('div'); + const headerHomeContent = document.createElement('div'); + headerHomeContent.className = 'gm-upload-disclaimer'; + + // Define small text zone on home view + headerHomeContent.appendChild(this.createTextDiv('gm-upload-disclaimer-txt', '

PLEASE NOTE
\ + GENYMOBILE INC., ASSUMES NO LIABILITY WHATSOEVER RESULTING FROM THE DOWNLOAD,\ + INSTALL AND USE OF GOOGLE PLAY SERVICES WITHIN YOUR VIRTUAL DEVICES. YOU ARE\ + SOLELY RESPONSIBLE FOR THE USE AND ASSUME ALL LIABILITY RELATED THERETO.\ + MOREOVER\ +

\ + GENYMOBILE INC. DISCLAIMS ANY WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,\ + INCLUDING, WITHOUT LIMITATION, IMPLIED WARRANTIES OF MERCHANTABILITY, OR FITNESS\ + FOR A PARTICULAR PURPOSE REGARDING THE COMPATIBILITY OF THE OPENGAPPS PACKAGES\ + WITH ANY VERSION OF GENYMOTION. IN NO EVENT SHALL GENYMOBILE INC. OR ITS AFFILIATES,\ + OR THEIR RESPECTIVE OFFICERS, DIRECTORS, EMPLOYEES, OR AGENTS BE LIABLE WITH RESPECT\ + TO YOUR DOWNLOAD OR USE OF THE GOOGLE PLAY SERVICES AND YOU RELEASE GENYMOBILE INC.\ + FROM ANY LIABILITY RELATED THERETO. YOU AGREE TO DEFEND, INDEMNIFY AND HOLD HARMLESS\ + GENYMOBILE INC. FOR ANY CLAIMS OR COSTS RELATED TO YOUR USE OR DOWNLOAD OF THE GOOGLE\ + PLAY SERVICES.\ +

')); + + // Slit in header and bottom part + homeContent.appendChild(headerHomeContent); + + // Define 2 buttons at widget bottom + const bottomButtonsContainer = document.createElement('div'); + bottomButtonsContainer.className = 'gm-upload-main-bottom-buttons'; + + const buttons = this.createButtonsGroup('Back', (event) => { + event.preventDefault(); + this.flashing = false; + this.displayStep('homeScreen'); + }, 'Install', (event) => { + event.preventDefault(); + this.flashing = true; + const json = { + channel: 'systempatcher', messages: [ + 'install opengapps' + ] + }; + this.instance.sendEvent(json); + this.displayStep('uploadScreen'); + }); + + bottomButtonsContainer.appendChild(buttons[LEFT]); + bottomButtonsContainer.appendChild(buttons[RIGHT]); + + // Add buttons and all home content view for this widget in the DOM + homeContent.appendChild(bottomButtonsContainer); + + return { + body: homeContent, + title: this.i18n.UPLOADER_DISCLAIMER || 'You are about to install Open GApps on your virtual device', + }; + } + + /** + * Create and return the "progress" file upload screen. + * + * @return {Object} HTMLElement & title for this screen. + */ + createUploadScreen() { + // Main div on the upload page of the Opengapps widget + const uploadContent = document.createElement('div'); + const headerUploadContent = document.createElement('div'); + headerUploadContent.className = 'gm-upload-in-progress'; + + // Define small text zone on upload view + const txtProgress = this.createTextDiv('gm-upload-in-progress-txt-progress', ''); + const txtPercent = this.createTextDiv('gm-upload-in-progress-txt-percent', ''); + const bgPercentBar = this.createTextDiv('gm-upload-in-progress-bg-percent', ''); + const percentbar = this.createTextDiv('gm-upload-in-progress-percent', ''); + + percentbar.style.width = '0%'; + bgPercentBar.appendChild(percentbar); + + headerUploadContent.appendChild(txtProgress); + headerUploadContent.appendChild(txtPercent); + headerUploadContent.appendChild(bgPercentBar); + + // Slit in header and bottom part + uploadContent.appendChild(headerUploadContent); + + // Define 2 buttons at widget bottom + const bottomButtonsContainer = document.createElement('div'); + bottomButtonsContainer.className = 'gm-upload-main-bottom-buttons'; + + const buttons = this.createButtonsGroup(null, null, 'Cancel', (event) => { + event.preventDefault(); + const json = { + channel: 'systempatcher', messages: [ + 'cancel' + ] + }; + this.instance.sendEvent(json); + this.displayStep('disclaimerScreen'); + }); + + bottomButtonsContainer.appendChild(buttons[RIGHT]); + + // Add buttons and all upload content view for this widget in the DOM + uploadContent.appendChild(bottomButtonsContainer); + + return { + body: uploadContent, + title: this.i18n.UPLOADER_INPROGRESS || 'Downloading', + }; + } + + /** + * Create and return the "success" file upload screen. + * + * @return {Object} HTMLElement & title for this screen. + */ + createSuccessStep() { + // Main div on the home page of the Open GApps widget + const homeContent = document.createElement('div'); + const headerHomeContent = document.createElement('div'); + headerHomeContent.className = 'gm-upload-success'; + + // Define image on home view of Open GApps popup + headerHomeContent.appendChild(this.createIconDiv('gm-upload-success-img')); + + // Small text below the image + headerHomeContent.appendChild(this.createTextDiv('gm-upload-success-caption', 'Congratulation!')); + + // Define small text zone on home view + headerHomeContent.appendChild(this.createTextDiv( + 'gm-upload-success-txt', '

Open GApps have been successfully \ + installed on the virtual device.
Please restart the virtual device to complete the installation.
\ + You will be redirected to the Open GApps website.

' + )); + + // Reboot button + headerHomeContent.appendChild(this.createButton('gm-upload-success-button', 'Reboot device', (event) => { + event.preventDefault(); + const json = { + channel: 'systempatcher', messages: [ + 'reboot' + ] + }; + this.instance.sendEvent(json); + this.toggleWidget(); + })); + + // Slit in header and bottom part + homeContent.appendChild(headerHomeContent); + + return { + body: homeContent, + title: this.i18n.UPLOADER_SUCCESS || 'Open GApps successfully installed', + }; + } + + /** + * Create and return the "error" file upload screen. + * + * @return {Object} HTMLElement & title for this screen. + */ + createErrorStep() { + // Main div on the home page of the Open GApps widget + const homeContent = document.createElement('div'); + const headerHomeContent = document.createElement('div'); + headerHomeContent.className = 'gm-upload-error'; + + // Define image on home view of Open GApps popup + headerHomeContent.appendChild(this.createIconDiv('gm-upload-error-img')); + + // Small text below the image + headerHomeContent.appendChild(this.createTextDiv('gm-upload-error-caption', 'Failed to install Open GApps')); + + // Slit in header and bottom part + homeContent.appendChild(headerHomeContent); + + return { + body: homeContent, + title: this.i18n.UPLOADER_FAILURE || 'We\'ve got a problem…', + }; + } + + /** + * Create and return a buttons group. + * + * @param {string} leftText Left button text. + * @param {Function} leftCallback Left button click callback. + * @param {string} rightText Right button text. + * @param {Function} rightCallback Right button click callback. + * @return {HTMLElement} The buttons group. + */ + createButtonsGroup(leftText, leftCallback, rightText, rightCallback) { + const buttons = [null, null]; + + if (leftText) { + buttons[LEFT] = this.createButton( + 'gm-upload-main-bottom-buttons-left gm-dont-close', leftText, leftCallback + ); + } + + if (rightText) { + buttons[RIGHT] = this.createButton( + 'gm-upload-main-bottom-buttons-right gm-dont-close', rightText, rightCallback + ); + } + + return buttons; + } + + /** + * Create and return a button. + * + * @param {string} className CSS class to apply to the element. + * @param {string} text Button text content. + * @param {Function} onClick Click callback function. + * @return {HTMLElement} The created button. + */ + createButton(className, text, onClick) { + const button = document.createElement('div'); + button.className = className; + button.innerHTML = text; + button.onclick = onClick; + return button; + } + + /** + * Create and return an icon element. + * + * @param {string} className CSS class to apply to the element. + * @return {HTMLElement} The created icon. + */ + createIconDiv(className) { + const icon = document.createElement('span'); + icon.className = 'gm-upload-icon ' + className; + return icon; + } + + /** + * Create and return a text element. + * + * @param {string} className CSS class to apply to the element. + * @param {string} text Block text content. + * @return {HTMLElement} The created text. + */ + createTextDiv(className, text) { + const textCloud = document.createElement('div'); + textCloud.className = className; + textCloud.innerHTML = text; + return textCloud; + } +}; diff --git a/src/plugins/Fullscreen.js b/src/plugins/Fullscreen.js new file mode 100644 index 0000000..124798e --- /dev/null +++ b/src/plugins/Fullscreen.js @@ -0,0 +1,131 @@ +'use strict'; + +/** + * Display fullscreen plugin. + * Gives the ability to display the player on the whole screen. + */ +module.exports = class Fullscreen { + /** + * Plugin initialization. + * + * @param {Object} instance Associated instance. + */ + constructor(instance) { + // Reference instance + this.instance = instance; + + // we register for fullscreen event changes + if (document.addEventListener) { + document.addEventListener('webkitfullscreenchange', this.onFullscreenEvent.bind(this), false); + document.addEventListener('fullscreenchange', this.onFullscreenEvent.bind(this), false); + } + + // Display widget + this.renderToolbarButton(); + } + + /** + * Add the button to the player toolbar. + */ + renderToolbarButton() { + const toolbars = this.instance.getChildByClass(this.instance.root, 'gm-toolbar'); + if (!toolbars) { + return; // if we don't have toolbar, we can't spawn the widget + } + + const toolbar = toolbars.children[0]; + + if (this.isTemplateFullscreen()) { + /** + * If the template is fullscreen, there is a splash screen that ask the user + * to allow the fullscreen. It is needed due to HTML5 requirements. + */ + const fullscreenMessage = this.instance.getChildByClass(this.instance.root, 'gm-fullscreen-message'); + fullscreenMessage.onclick = () => { + fullscreenMessage.classList.add('hide'); + this.instance.wrapper.classList.remove('hide'); + this.goFullscreen(this.instance.root); + }; + } else { + /** + * Else we add a button that will allows the user to set/unset the + * fullscreen for the given genycloud instance + */ + this.button = document.createElement('li'); + this.image = document.createElement('div'); + this.image.className = 'gm-icon-button gm-fullscreen-button'; + this.image.title = 'Fullscreen'; + this.button.appendChild(this.image); + toolbar.appendChild(this.button); + + // when clicked on the button, should we enter or exit fullscreen + this.button.onclick = () => { + if (this.fullscreenEnabled()) { + this.exitFullscreen(); + } else { + this.goFullscreen(this.instance.root); + } + }; + } + } + + /** + * Enter fullscreen mode. + * + * @param {HTMLElement} element DOM element to set fullscreen on. + */ + goFullscreen(element) { + this.instance.wrapper.classList.add('gm-fullscreen'); + this.image.classList.add('gm-active'); + if (element.requestFullscreen) { + element.requestFullscreen(); + } else if (element.webkitRequestFullscreen) { + element.webkitRequestFullscreen(); + } + } + + /** + * Determine whether fullscreen mode is active or not. + * + * @return {boolean} Whether fullscreen mode is active or not. + */ + fullscreenEnabled() { + return document.fullscreenElement + || document.webkitFullscreenElement; + } + + /** + * Exit fullscreen mode. + */ + exitFullscreen() { + this.instance.wrapper.classList.remove('gm-fullscreen'); + this.image.classList.remove('gm-active'); + if (!this.fullscreenEnabled()) { + return; // do not try to remove fulllscreen if it is not active + } + if (document.exitFullscreen) { + document.exitFullscreen(); + } else if (document.webkitExitFullscreen) { + document.webkitExitFullscreen(); + } + } + + /** + * Determine whether the template is configured to be displayed in fullscreen or not. + * + * @return {boolean} Whether the template is configured to be displayed in fullscreen or not. + */ + isTemplateFullscreen() { + return Boolean(this.instance.getChildByClass(this.instance.root, 'gm-fullscreen-message')); + } + + /** + * Fullscreen event listener. + */ + onFullscreenEvent() { + // if we lose fullscreen, we have to make sure that it has correctly exited + if (!this.fullscreenEnabled()) { + this.exitFullscreen(); + } + } +}; diff --git a/src/plugins/GPS.js b/src/plugins/GPS.js new file mode 100644 index 0000000..c364e3a --- /dev/null +++ b/src/plugins/GPS.js @@ -0,0 +1,578 @@ +'use strict'; + +const OverlayPlugin = require('./util/OverlayPlugin'); + +const log = require('loglevel'); +log.setDefaultLevel('debug'); + +/* global google */ + +/** + * Instance GPS plugin. + * Provides GPS control. + */ +module.exports = class GPS extends OverlayPlugin { + /** + * Plugin initialization. + * + * @param {Object} instance Associated instance. + * @param {Object} i18n Translations keys for the UI. + * @param {boolean} speedSupport Enable speed support. + */ + constructor(instance, i18n, speedSupport) { + super(instance); + + // Reference instance + this.instance = instance; + this.i18n = i18n || {}; + + // Register plugin + this.instance.gps = this; + + // Location fields + this.fields = ['altitude', 'longitude', 'latitude', 'accuracy', 'bearing']; + if (speedSupport) { + this.fields.push('speed'); + } + + // Map references + this.map = null; + if (typeof google !== 'undefined') { + this.elevationService = new google.maps.ElevationService(); + } else { + log.error('Cant find Google Maps API object, did you forget to embed it?'); + this.elevationService = false; + } + this.markers = []; + + // Let's use Dalvik as default value + this.mapLat = 65.9667; + this.mapLng = -18.5333; + this.elevation = 15.04444408; + + // The minimal zoom level of the map (if less, it will zoom automatically) + this.minimumZoomLevel = 8; + + // Display widget + this.renderToolbarButton(); + this.renderGPSForm(); + this.renderMapView(); + + // Listen for gps events: " " + this.instance.registerEventCallback('gps', (message) => { + const values = message.split(' '); + if (this.fields.includes(values[0]) && values.length >= 2) { + this.setFieldValue('gm-gps-' + values[0], values[1]); + } + }); + } + + /** + * Add the button to the player toolbar. + */ + renderToolbarButton() { + const toolbars = this.instance.getChildByClass(this.instance.root, 'gm-toolbar'); + if (!toolbars) { + return; // if we don't have toolbar, we can't spawn the widget + } + + const toolbar = toolbars.children[0]; + this.toolbarBtn = document.createElement('li'); + this.toolbarBtnImage = document.createElement('div'); + this.toolbarBtnImage.className = 'gm-icon-button gm-gps-button'; + this.toolbarBtnImage.title = this.i18n.GPS_TITLE || 'GPS'; + this.toolbarBtn.appendChild(this.toolbarBtnImage); + this.toolbarBtn.onclick = this.toggleForm.bind(this); + toolbar.appendChild(this.toolbarBtn); + } + + /** + * Render the widget: map view. + */ + renderMapView() { + // Create elements + this.mapWidget = document.createElement('div'); + this.mapview = document.createElement('div'); + + // Add capture button + const capture = document.createElement('button'); + capture.innerHTML = this.i18n.GPS_CAPTURE || 'Capture'; + capture.className = 'gm-gps-mapview-capture'; + capture.onclick = this.onMapClicked.bind(this); + + // Add cancel button + const cancel = document.createElement('button'); + cancel.innerHTML = this.i18n.GPS_CANCEL || 'Cancel'; + cancel.className = 'gm-gps-mapview-cancel'; + cancel.onclick = this.onHideMapButtonClicked.bind(this); + + // Setup + this.mapview.className = 'gm-mapview'; + this.mapWidget.className = 'gm-overlay gm-gps-mapview gm-hidden'; + this.mapWidget.appendChild(this.mapview); + this.mapWidget.appendChild(capture); + this.mapWidget.appendChild(cancel); + + // Render into document + this.overlays.push(this.mapWidget); + this.instance.root.appendChild(this.mapWidget); + } + + /** + * Load map, if available. + */ + loadMap() { + // Get form info + const info = this.getLocationInfo(); + + // Render map + if (typeof google !== 'undefined') { + this.map = new google.maps.Map(this.mapview, { + center: { + lat: info.latitude, + lng: info.longitude, + }, + zoom: this.minimumZoomLevel, + }); + + // Add initial marker for selection from form + this.addMapMarker(info.latitude, info.longitude); + + // Listen for new location + this.map.addListener('click', (event) => { + this.clearMarkers(); + // Add new marker / capture coords for click location + this.addMapMarker(event.latLng.lat(), event.latLng.lng()); + }); + } + } + + /** + * Display or hide the map view. + */ + toggleMapview() { + this.mapWidget.classList.toggle('gm-hidden'); + } + + /** + * Create a form field element. + * + * @param {string} name Input name. + * @param {string} label Input label. + * @param {string} value Input value. + * @param {string} min Input min attribute. + * @param {string} max Input max attribute. + * @return {HTMLElement} The created input. + */ + generateInput(name, label, value, min, max) { + const inputWrap = document.createElement('div'); + + const lab = document.createElement('label'); + lab.innerHTML = label; + inputWrap.appendChild(lab); + + const input = document.createElement('input'); + input.type = 'number'; + input.defaultValue = value; + input.min = min; + input.max = max; + input.className = 'gm-gps-' + name; + input.step = 'any'; + input.addEventListener('keyup', this.checkErrors.bind(this)); + inputWrap.appendChild(input); + + return inputWrap; + } + + /** + * Input form validation. + */ + checkErrors() { + let gotAnError = false; + this.fields.forEach((field) => { + const input = this.instance.getChildByClass(this.instance.root, 'gm-gps-' + field); + if (input.checkValidity() === false) { + input.classList.add('gm-error'); + gotAnError = true; + } else { + input.classList.remove('gm-error'); + } + }); + + this.instance.getChildByClass(this.instance.root, 'gm-gps-submit').disabled = gotAnError; + } + + /** + * Render the widget: controls view. + */ + renderGPSForm() { + // Create elements + this.formWidget = document.createElement('div'); + this.form = document.createElement('form'); + const formWrap = document.createElement('div'); + + // Generate title + const title = document.createElement('div'); + title.className = 'gm-title'; + title.innerHTML = this.i18n.GPS_TITLE || 'GPS'; + this.form.appendChild(title); + + // Generate form inputs + const inputs = document.createElement('div'); + inputs.className = 'gm-col'; + + const latitudeLabel = this.i18n.GPS_LATITUDE || 'Latitude (°)'; + inputs.appendChild(this.generateInput( + 'latitude', latitudeLabel, this.mapLat, -90.0, 90.0 + )); + + const longitudeLabel = this.i18n.GPS_LONGITUDE || 'Longitude (°)'; + inputs.appendChild(this.generateInput( + 'longitude', longitudeLabel, this.mapLng, -180.0, 180.0 + )); + + const altitudeLabel = this.i18n.GPS_ALTITUDE || 'Altitude (m)'; + inputs.appendChild(this.generateInput( + 'altitude', altitudeLabel, this.elevation, -10000, 10000 + )); + + const accuracyLabel = this.i18n.GPS_ACCURACY || 'Accuracy (m)'; + inputs.appendChild(this.generateInput('accuracy', accuracyLabel, 0, 0, 200)); + + const bearingLabel = this.i18n.GPS_BEARING || 'Bearing (°)'; + inputs.appendChild(this.generateInput('bearing', bearingLabel, 0, 0, 360)); + + if (this.fields.includes('speed')) { + const speedLabel = this.i18n.GPS_SPEED || 'Speed (m/s)'; + inputs.appendChild(this.generateInput('speed', speedLabel, 0, 0, 399.99)); + } + + // Generate right side of form + const right = document.createElement('div'); + const rightMapWrap = document.createElement('div'); + const map = document.createElement('button'); + this.rightGeolocWrap = document.createElement('div'); + this.geolocBtn = document.createElement('button'); + + right.className = 'gm-col'; + rightMapWrap.className = 'map-wrap'; + + map.className = 'map'; + map.innerHTML = this.i18n.GPS_MAP || 'MAP'; + map.onclick = this.onOpenMapButtonClicked.bind(this); + + this.rightGeolocWrap.className = 'gm-geoloc-wrap'; + this.geolocBtn.className = 'gm-gps-geoloc'; + this.geolocBtn.innerHTML = this.i18n.GPS_GEOLOC || 'My position'; + this.geolocBtn.onclick = this.onGeolocButtonClicked.bind(this); + + rightMapWrap.appendChild(map); + this.rightGeolocWrap.appendChild(this.geolocBtn); + right.appendChild(rightMapWrap); + right.appendChild(this.rightGeolocWrap); + + // Build form + formWrap.className = 'gm-wrap'; + formWrap.appendChild(inputs); + formWrap.appendChild(right); + this.form.appendChild(formWrap); + + // Attach submit button + const button = document.createElement('button'); + button.innerHTML = this.i18n.GPS_SUBMIT || 'Submit'; + button.className = 'gm-gps-submit'; + button.onclick = this.sendDataToInstance.bind(this); + this.form.appendChild(button); + + // Setup + this.formWidget.className = 'gm-overlay gm-gps-controls gm-hidden'; + + // Add close button + const close = document.createElement('div'); + close.className = 'gm-close-btn'; + close.onclick = this.toggleForm.bind(this); + + this.formWidget.appendChild(close); + this.formWidget.appendChild(this.form); + + // Render into document + this.overlays.push(this.formWidget); + this.instance.root.appendChild(this.formWidget); + } + + /** + * Display or hide the controls view. + */ + toggleForm() { + // Notify other callers + if (this.formWidget.classList.contains('gm-hidden')) { + this.instance.emit('close-overlays'); + this.instance.emit('keyboard-disable'); + } else { + this.instance.emit('keyboard-enable'); + } + + this.checkForGeolocation(); + + // Toggle display + this.formWidget.classList.toggle('gm-hidden'); + this.mapWidget.classList.add('gm-hidden'); + this.toolbarBtnImage.classList.toggle('gm-active'); + } + + /** + * Set geolocation button availability. + * + * @param {boolean} enabled Geolocation availability. + */ + setGeolocButtonAvailability(enabled) { + this.geolocBtn.disabled = !enabled; + if (enabled) { + this.rightGeolocWrap.title = this.i18n.GPS_GEOLOC_TOOLTIP || 'Get my position from browser location'; + } else { + this.rightGeolocWrap.title = this.i18n.GPS_NOGEOLOC_TOOLTIP || 'Geolocation not supported'; + } + } + + /** + * Open map view clicked. + * + * @param {Event} event Event. + */ + onOpenMapButtonClicked(event) { + event.preventDefault(); + this.toggleMapview(); + this.loadMap(); + } + + /** + * Geolocation button clicked. + * + * @param {Event} event Event. + */ + onGeolocButtonClicked(event) { + event.preventDefault(); + this.getLocation(); + } + + /** + * Map view clicked. + * + * @param {Event} event Event. + */ + onMapClicked(event) { + event.preventDefault(); + + // Update fields + this.setFieldValue('gm-gps-latitude', this.mapLat); + this.setFieldValue('gm-gps-longitude', this.mapLng); + this.setFieldValue('gm-gps-altitude', this.elevation); + + // Hide mapview + this.toggleMapview(); + } + + /** + * Hide map view button clicked. + * + * @param {Event} event Event. + */ + onHideMapButtonClicked(event) { + event.preventDefault(); + + this.mapWidget.classList.add('gm-hidden'); + } + + /** + * Send information to instance. + * + * @param {Event} event Event. + */ + sendDataToInstance(event) { + event.preventDefault(); + + const json = this.buildEventJson(); + if (json.messages.length) { + this.instance.sendEvent(json); + } + + this.toggleForm(); + } + + /** + * Get client geolocation. + */ + getLocation() { + if (!navigator.geolocation) { + return; + } + + navigator.geolocation.getCurrentPosition((position) => { + if (!position || !position.coords) { + return; + } + + this.fields.forEach((field) => { + if (position.coords[field]) { + this.setFieldValue('gm-gps-' + field, position.coords[field]); + } + }); + // Get altitude from elevation service if we don't have any + if (!position.coords.altitude && this.elevationService && + position.coords.latitude && position.coords.longitude) { + const location = new google.maps.LatLng(position.coords.latitude, position.coords.longitude); + this.elevationService.getElevationForLocations({ + 'locations': [location], + }, (results, status) => { + if (status === 'OK') { + // Retrieve the first result + if (results[0]) { + this.setFieldValue('gm-gps-altitude', results[0].elevation); + } + } + }); + } + }); + } + + /** + * Check browser geolocation capability and update UI accordingly. + */ + checkForGeolocation() { + if ('geolocation' in navigator) { + navigator.geolocation.getCurrentPosition(() => { + this.setGeolocButtonAvailability(true); + }, () => { + this.setGeolocButtonAvailability(false); + }); + } else { + this.setGeolocButtonAvailability(false); + } + } + + /** + * Set the value of the given form input according. + * + * @param {HTMLElement} field Form input to update. + * @param {string} value Value to set. + */ + setFieldValue(field, value) { + value = Number(value); + if (Number.isNaN(value)) { + return; + } + + const inputField = this.instance.getChildByClass(this.instance.root, field); + if (!inputField) { + return; + } + + if (inputField.max) { + value = Math.min(value, inputField.max); + } + if (inputField.min) { + value = Math.max(value, inputField.min); + } + + inputField.value = value; + } + + /** + * Extract location info from inputs. + * + * @return {Object} Geolocation data. + */ + getLocationInfo() { + const info = {}; + this.fields.forEach((fieldName) => { + const field = this.instance.getChildByClass(this.instance.root, 'gm-gps-' + fieldName); + if (!field) { + log.debug(fieldName + ' field not found.'); + return; + } + let value = Number(field.value); + if (Number.isNaN(value)) { + return; + } + + if (field.max) { + value = Math.min(value, field.max); + } + if (field.min) { + value = Math.max(value, field.min); + } + + info[fieldName] = value; + }); + return info; + } + + /** + * Format GPS event to be send to the instance. + * + * @return {Object} GPS event. + */ + buildEventJson() { + const event = {channel: 'gps', messages: []}; + const info = this.getLocationInfo(); + this.fields.forEach((field) => { + event.messages.push('set ' + field + ' ' + info[field]); + }); + + if (event.messages.length) { + // make sure GPS is started + event.messages.push('enable'); + } + return event; + } + + /** + * Adds new marker at given coords. + * + * @param {number} lat Latitude of the marker. + * @param {number} lng Longitude of the marker. + */ + addMapMarker(lat, lng) { + this.mapLat = lat; + this.mapLng = lng; + + const marker = new google.maps.Marker({ + position: { + lat: this.mapLat, + lng: this.mapLng, + }, + map: this.map, + }); + this.markers.push(marker); + + // Center map and zoom on position when needed + if (this.map && this.map.getZoom() < this.minimumZoomLevel) { + this.map.setCenter(marker.getPosition()); + this.map.setZoom(this.minimumZoomLevel); + } + + if (this.elevationService) { + const location = new google.maps.LatLng(lat, lng); + this.elevationService.getElevationForLocations({ + 'locations': [location], + }, (results, status) => { + if (status === 'OK') { + // Retrieve the first result + if (results[0]) { + this.elevation = results[0].elevation; + } + } + }); + } + } + + /** + * Removes all existing markers from the map. + */ + clearMarkers() { + this.markers.forEach((marker) => { + marker.setMap(null); + }); + this.markers = []; + } +}; diff --git a/src/plugins/IOThrottling.js b/src/plugins/IOThrottling.js new file mode 100644 index 0000000..28a02b8 --- /dev/null +++ b/src/plugins/IOThrottling.js @@ -0,0 +1,304 @@ +'use strict'; + +const OverlayPlugin = require('./util/OverlayPlugin'); + +const PROFILES = require('./util/iothrottling-profiles'); +const BYTES_PER_KILOBYTE = 1024; +const BYTES_PER_MEGABYTE = BYTES_PER_KILOBYTE << 10; + +/** + * Instance IO throttling plugin. + * Provides disk I/O control. + */ +module.exports = class IOThrottling extends OverlayPlugin { + /** + * Plugin initialization. + * + * @param {Object} instance Associated instance. + * @param {Object} i18n Translations keys for the UI. + */ + constructor(instance, i18n) { + super(instance); + + // Reference instance + this.instance = instance; + this.i18n = i18n || {}; + + // Register plugin + this.instance.diskIO = this; + + this.fields = {}; + + // Render components + this.renderToolbarButton(); + this.renderWidget(); + + // Listen for initial diskio + this.instance.registerEventCallback('BLK', this.setActive.bind(this)); + + // Listen for diskio messages: "readbyterate " (or "cachecleared") + this.instance.registerEventCallback('diskio', (message) => { + const values = message.split(' '); + if (values[0] === 'readbyterate' && values.length === 2) { + this.updateDiskIOValues(values[1] / BYTES_PER_MEGABYTE); + } + }); + } + + /** + * Add the button to the player toolbar. + */ + renderToolbarButton() { + const toolbars = this.instance.getChildByClass(this.instance.root, 'gm-toolbar'); + if (!toolbars) { + return; // if we don't have toolbar, we can't spawn the widget + } + + const toolbar = toolbars.children[0]; + this.toolbarBtn = document.createElement('li'); + this.toolbarBtnImage = document.createElement('div'); + this.toolbarBtnImage.className = 'gm-icon-button gm-iothrottling-button'; + this.toolbarBtnImage.title = this.i18n.IOTHROTTLING_TITLE || 'Disk I/O'; + this.toolbarBtn.appendChild(this.toolbarBtnImage); + this.toolbarBtn.onclick = this.toggleWidget.bind(this); + toolbar.appendChild(this.toolbarBtn); + } + + /** + * Render the widget. + */ + renderWidget() { + // Create elements + this.widget = document.createElement('div'); + this.form = document.createElement('form'); + + // Generate title + const title = document.createElement('div'); + title.className = 'gm-title'; + title.innerHTML = this.i18n.IOTHROTTLING_TITLE || 'Disk I/O'; + this.form.appendChild(title); + + // Generate input rows + const inputs = document.createElement('div'); + inputs.className = 'gm-inputs'; + + const IOThrottlingLabel = this.i18n.IOTHROTTLING_PROFILE || 'Profile'; + inputs.innerHTML = ''; + + // Create select + this.select = document.createElement('select'); + this.select.className = 'gm-iothrottling-select'; + const defaultOption = new Option(this.i18n.IOTHROTTLING_PROFILE_NONE || 'None'); + this.select.add(defaultOption); + this.select.onchange = this.changeProfile.bind(this); + inputs.appendChild(this.select); + + // Add option for each child + PROFILES.forEach((profile) => { + const option = new Option(profile.label, profile.name); + this.select.add(option); + }); + + this.readByteRateDiv = document.createElement('div'); + this.readByteRateDiv.classList.add('gm-fields'); + const readByteRateLabel = document.createElement('label'); + readByteRateLabel.innerHTML = this.i18n.IOTHROTTLING_READ_BYTERATE || 'Read speed limit:'; + this.readByteRate = document.createElement('input'); + this.readByteRate.className = 'gm-iothrottling-readbyterate'; + this.readByteRate.placeholder = this.i18n.IOTHROTTLING_READ_BYTERATE_EXAMPLE || 'eg: 100'; + this.readByteRate.title = this.i18n.READ_BYTE_RATE || 'Read speed limit'; + this.readByteRate.required = true; + this.readByteRate.pattern = '[0-9]*'; + this.readByteRateDiv.appendChild(readByteRateLabel); + const readByteRateSpeed = document.createElement('label'); + readByteRateSpeed.innerHTML = this.i18n.IOTHROTTLING_BYTERATE_UNIT || 'MiB per sec'; + readByteRateSpeed.classList.add('gm-units'); + this.readByteRateDiv.appendChild(readByteRateSpeed); + this.readByteRateDiv.appendChild(this.readByteRate); + + // Add submit button + this.submitBtn = document.createElement('button'); + this.submitBtn.className = 'gm-iothrottling-update'; + this.submitBtn.innerHTML = this.i18n.IOTHROTTLING_UPDATE || 'Update'; + this.submitBtn.onclick = this.sendDataToInstance.bind(this); + + // Add clear cache button + this.clearCacheBtn = document.createElement('button'); + this.clearCacheBtn.className = 'gm-iothrottling-clearcache'; + this.clearCacheBtn.innerHTML = this.i18n.IOTHROTTLING_CLEAR_CACHE || 'Clear cache'; + this.clearCacheBtn.onclick = this.clearCache.bind(this); + const clearCacheDiv = document.createElement('div'); + clearCacheDiv.appendChild(this.clearCacheBtn); + + // Setup + this.form.appendChild(inputs); + this.form.appendChild(this.readByteRateDiv); + this.form.appendChild(clearCacheDiv); + this.form.appendChild(this.submitBtn); + + this.setFieldsReadOnly(true); + this.resetFields('0'); + this.displayFields(false); + + this.widget.className = 'gm-overlay gm-iothrottling-plugin gm-hidden'; + + // Add close button + const close = document.createElement('div'); + close.className = 'gm-close-btn'; + close.onclick = this.toggleWidget.bind(this); + + this.widget.appendChild(close); + this.widget.appendChild(this.form); + + // Render into document + this.overlays.push(this.widget); + this.instance.root.appendChild(this.widget); + } + + /** + * Set custom fields read-only or not. + * + * @param {boolean} readOnly Desired read-only status. + */ + setFieldsReadOnly(readOnly) { + this.readByteRate.readOnly = readOnly; + } + + /** + * Reset custom fields value. + * + * @param {number} value Desired value. + */ + resetFields(value) { + value = typeof value !== 'undefined' ? value : ''; + this.readByteRate.value = value; + } + + /** + * Toggle custom fields input visibility. + * + * @param {boolean} display Whether or not inputs should be visible. + */ + displayFields(display) { + if (display) { + this.readByteRateDiv.classList.remove('gm-hidden'); + } else { + this.readByteRateDiv.classList.add('gm-hidden'); + } + } + + /** + * Display or hide the widget. + */ + toggleWidget() { + // Notify other callers + if (this.widget.classList.contains('gm-hidden')) { + this.instance.emit('close-overlays'); + this.instance.emit('keyboard-disable'); + } else { + this.instance.emit('keyboard-enable'); + } + + // Toggle display + this.widget.classList.toggle('gm-hidden'); + this.toolbarBtnImage.classList.toggle('gm-active'); + } + + /** + * Send information to instance. + * + * @param {Event} event Event. + */ + sendDataToInstance(event) { + event.preventDefault(); + + if (this.form.checkValidity()) { + const json = { + channel: 'diskio', messages: [ + 'set readbyterate ' + this.readByteRate.value * BYTES_PER_MEGABYTE, + 'clearcache' + ] + }; + this.instance.sendEvent(json); + this.toggleWidget(); + } + } + + /** + * Clear cache button handler. + * + * @param {Event} event Event. + */ + clearCache(event) { + event.preventDefault(); + + const json = {channel: 'diskio', messages: ['clearcache']}; + this.instance.sendEvent(json); + } + + /** + * Handles profile change. + */ + changeProfile() { + const profile = PROFILES.find((elem) => elem.name === this.select.value); + if (profile && profile.name !== 'Custom') { + this.loadDetails(profile); + this.displayFields(true); + } else if (profile && profile.name === 'Custom') { + this.setFieldsReadOnly(false); + this.displayFields(true); + } else { + this.resetFields('0'); + this.displayFields(false); + } + } + + /** + * Handles disk I/O parameters changes. Keeps UI in sync with the instance state. + * + * @param {number} readSpeed Read byte rate. + */ + updateDiskIOValues(readSpeed) { + readSpeed = Number(readSpeed); + + if (Number.isNaN(readSpeed) || readSpeed <= 0) { + this.select.value = this.i18n.IOTHROTTLING_PROFILE_NONE || 'None'; + this.resetFields('0'); + this.displayFields(false); + return; + } + + this.readByteRate.value = readSpeed; + const profile = PROFILES.find((elem) => elem.readByteRate === readSpeed); + if (profile && profile.name !== 'Custom') { + this.select.value = profile.name; + this.loadDetails(profile); + this.displayFields(true); + } else { + this.select.value = 'Custom'; + this.setFieldsReadOnly(false); + this.displayFields(true); + } + } + + /** + * Load fields with the given profile info. + * + * @param {Object} profile Selected profile. + */ + loadDetails(profile) { + if (profile.name !== 'Custom') { + this.setFieldsReadOnly(true); + this.readByteRate.value = profile.readByteRate; + } + } + + /** + * Activate disk I/O throttling. Keeps UI in sync with the instance state. + * + * @param {number} readSpeed Read byte rate. + */ + setActive(readSpeed) { + this.updateDiskIOValues(Number(readSpeed) / BYTES_PER_KILOBYTE); + } +}; diff --git a/src/plugins/Identifiers.js b/src/plugins/Identifiers.js new file mode 100644 index 0000000..cbafc6e --- /dev/null +++ b/src/plugins/Identifiers.js @@ -0,0 +1,310 @@ +'use strict'; + +const OverlayPlugin = require('./util/OverlayPlugin'); + +const HEX = '0123456789abcdef'; +const DIGITS = '0123456789'; + +/** + * Instance identifiers plugin. + * Provides device ID (IMEI) and Android ID control. + */ +module.exports = class Identifiers extends OverlayPlugin { + /** + * Plugin initialization. + * + * @param {Object} instance Associated instance. + * @param {Object} i18n Translations keys for the UI. + */ + constructor(instance, i18n) { + super(instance); + + // Reference instance + this.instance = instance; + this.i18n = i18n || {}; + + // Register plugin + this.instance.identifiers = this; + + // Initial state + this.invalidAndroidId = false; + this.invalidDeviceId = false; + + // Render components + this.renderToolbarButton(); + this.renderWidget(); + + // Listen for IDs from player + this.instance.registerEventCallback('ANDROID_ID', (payload) => { + this.androidInput.value = payload; + }); + this.instance.registerEventCallback('IMEI', (payload) => { + this.deviceInput.value = payload; + }); + + // Listen for settings messages: "parameter :" + this.instance.registerEventCallback('settings', (message) => { + const values = message.split(' '); + if (values[0] !== 'parameter' || values.length < 2) { + return; + } + + const deviceId = values[1].match(/(device_id:)(\w+)/); + if (deviceId) { + this.deviceInput.value = deviceId[2]; + } + const androidId = values[1].match(/(android_id:)(\w+)/); + if (androidId) { + this.androidInput.value = androidId[2]; + } + }); + } + + /** + * Add the button to the player toolbar. + */ + renderToolbarButton() { + const toolbars = this.instance.getChildByClass(this.instance.root, 'gm-toolbar'); + if (!toolbars) { + return; // if we don't have toolbar, we can't spawn the widget + } + + const toolbar = toolbars.children[0]; + this.toolbarBtn = document.createElement('li'); + this.toolbarBtnImage = document.createElement('div'); + this.toolbarBtnImage.className = 'gm-icon-button gm-identifiers-button'; + this.toolbarBtnImage.title = this.i18n.IDENTIFIERS_TITLE || 'Identifiers'; + this.toolbarBtn.appendChild(this.toolbarBtnImage); + this.toolbarBtn.onclick = this.toggleWidget.bind(this); + toolbar.appendChild(this.toolbarBtn); + } + + /** + * Render the widget. + */ + renderWidget() { + // Create elements + this.widget = document.createElement('div'); + this.container = document.createElement('div'); + + // Generate title + const title = document.createElement('div'); + title.className = 'gm-title'; + title.innerHTML = this.i18n.IDENTIFIERS_TITLE || 'Identifiers'; + this.container.appendChild(title); + + // Generate input rows + const inputs = document.createElement('div'); + inputs.className = 'gm-inputs'; + + // Build field list + const android = this.generateInput( + 'android', 'Android ID', '', + this.generateRandomAndroidId.bind(this), + this.validateAndroidId.bind(this) + ); + const device = this.generateInput( + 'device', 'Device ID', '(IMEI/MEID)', + this.generateRandomDeviceId.bind(this), + this.validateDeviceId.bind(this) + ); + inputs.appendChild(android); + inputs.appendChild(device); + + this.submitBtn = document.createElement('button'); + this.submitBtn.innerHTML = this.i18n.IDENTIFIERS_UPDATE || 'Update'; + this.submitBtn.className = 'gm-action gm-identifiers-update'; + inputs.appendChild(this.submitBtn); + this.submitBtn.onclick = this.sendDataToInstance.bind(this); + + this.container.appendChild(inputs); + + // Setup + this.widget.className = 'gm-overlay gm-identifiers-plugin gm-hidden'; + + // Add close button + const close = document.createElement('div'); + close.className = 'gm-close-btn'; + close.onclick = this.toggleWidget.bind(this); + + this.widget.appendChild(close); + this.widget.appendChild(this.container); + + // Render into document + this.overlays.push(this.widget); + this.instance.root.appendChild(this.widget); + } + + /** + * Display or hide the widget. + */ + toggleWidget() { + // Notify other callers + if (this.widget.classList.contains('gm-hidden')) { + this.instance.emit('close-overlays'); + this.instance.emit('keyboard-disable'); + } else { + this.instance.emit('keyboard-enable'); + } + + // Toggle display + this.widget.classList.toggle('gm-hidden'); + this.toolbarBtnImage.classList.toggle('gm-active'); + } + + /** + * Send information to instance. + * + * @param {Event} event Event. + */ + sendDataToInstance(event) { + event.preventDefault(); + + const androidId = this.androidInput.value; + const deviceId = this.deviceInput.value; + + if (androidId && this.androidInput.checkValidity()) { + const json = { + channel : 'framework' , messages : [ + 'set parameter android_id:' + androidId + ] + }; + this.instance.sendEvent(json); + } + + if (deviceId && this.deviceInput.checkValidity()) { + const json = { + channel : 'settings' , messages : [ + 'set parameter device_id:' + deviceId + ] + }; + this.instance.sendEvent(json); + } + this.toggleWidget(); + } + + /** + * Generate a new random Android ID. + * + * @param {Event} event Event. + */ + generateRandomAndroidId(event) { + if (event) { + event.preventDefault(); + } + + this.androidInput.value = this.generateHash(16, HEX); + this.invalidAndroidId = false; + this.checkErrors(); + } + + /** + * Validate Android ID input value. + */ + validateAndroidId() { + this.invalidAndroidId = !this.androidInput.checkValidity(); + this.checkErrors(); + } + + /** + * Generate a new random Device ID. + * + * @param {Event} event Event. + */ + generateRandomDeviceId(event) { + if (event) { + event.preventDefault(); + } + + this.deviceInput.value = this.generateHash(15, DIGITS); + this.invalidDeviceId = false; + this.checkErrors(); + } + + /** + * Validate Device ID input value. + */ + validateDeviceId() { + this.invalidDeviceId = !this.deviceInput.checkValidity(); + this.checkErrors(); + } + + /** + * Input form validation. + */ + checkErrors() { + this.androidInput.classList[this.invalidAndroidId ? 'add' : 'remove']('gm-error'); + this.deviceInput.classList[this.invalidDeviceId ? 'add' : 'remove']('gm-error'); + + this.submitBtn.disabled = this.invalidAndroidId || this.invalidDeviceId; + } + + /** + * Create a form field element. + * + * @param {string} type Input type. + * @param {string} label Input label. + * @param {string} description Input description. + * @param {string} generationMethod Input random value generation method. + * @param {string} validationMethod Input value validation method. + * @return {HTMLElement} The created input. + */ + generateInput(type, label, description, generationMethod, validationMethod) { + const field = document.createElement('div'); + const inputWrap = document.createElement('div'); + const input = document.createElement('input'); + const button = document.createElement('button'); + + inputWrap.className = 'gm-input-group'; + input.className = 'gm-identifier-' + type + '-input'; + input.type = 'text'; + input.required = true; + input.addEventListener('keyup', validationMethod); + inputWrap.appendChild(input); + + // Some customization + if (type === 'device') { + input.maxLength = 15; + input.pattern = '['+HEX+']{14,15}'; + } else if (type === 'android') { + input.maxLength = 16; + input.pattern = '['+HEX+']{16}'; + } + + button.className = 'gm-identifier-' + type + '-generate'; + button.innerHTML = this.i18n.IDENTIFIERS_GENERATE || 'Generate'; + button.onclick = generationMethod; + inputWrap.appendChild(button); + + field.className = 'gm-identifier-' + type; + field.innerHTML = ''; + field.appendChild(inputWrap); + + this[type + 'Input'] = input; + this[type + 'Gen'] = button; + + return field; + } + + /** + * Generate random 16 chars hash. + * + * @param {number} length Hash length. + * @param {string} alphabet Characters to use in for hash. + * @return {string} The generated hash. + */ + generateHash(length, alphabet) { + let hash = ''; + + for (let i = 0; i < length; i++) { + hash += alphabet.charAt(Math.floor(Math.random() * alphabet.length)); + } + + return hash; + } +}; diff --git a/src/plugins/KeyboardEvents.js b/src/plugins/KeyboardEvents.js new file mode 100644 index 0000000..60a4ec5 --- /dev/null +++ b/src/plugins/KeyboardEvents.js @@ -0,0 +1,228 @@ +'use strict'; + +/** + * List of invisible key that can be pressed. + * For values, see http://doc.qt.io/qt-4.8/qt.html & https://github.com/ccampbell/mousetrap/blob/master/mousetrap.js + */ +const INVISIBLE_KEYS = { + 8: '0x01000003', // backspace + 9: '0x01000001', // tab + 13: '0x01000005', // enter + 16: '0x01000020', // shift + 17: '0x01000021', // ctrl + 18: '0x01000023', // alt + 20: '0x01000024', // capslock + 27: '0x01000000', // escape + 32: '0x20', // space + 33: '0x01000016', // pageup + 34: '0x01000017', // pagedown + 35: '0x01000011', // end + 36: '0x01000010', // home + 37: '0x01000012', // left + 38: '0x01000013', // up + 39: '0x01000014', // right + 40: '0x01000015', // down + 45: '0x01000006', // ins + 46: '0x01000007', // del + /** + * Do not propagate Meta to Android. It disables copy/cut/paste special keys when pressed + * 91: '0x01000022', // meta + * 93: '0x01000022', // meta + * 224: '0x01000022', // meta + */ +}; + +const CTRL_SHORTCUT_KEYS = { + 67: '0x010000cf', // Copy + 86: '0x010000e2', // Paste + 88: '0x010000d0', // Cut +}; + +/** + * Instance keyboard plugin. + * Translate and forward keyboard events to instance. + */ +module.exports = class KeyboardEvents { + /** + * Plugin initialization. + * + * @param {Object} instance Associated instance. + */ + constructor(instance) { + // Reference instance + this.instance = instance; + + // Register plugin + this.instance.keyboardEvents = this; + this.instance.keyboardEventsEnabled = true; + + this.transmitKeys = true; + this.isListenerAdded = false; + this.currentlyPressedKeys = new Map(); + + // Listen for keyboard disable + this.instance.registerEventCallback('keyboard-disable', () => { + this.transmitKeys = false; + }); + + // Listen for keyboard enable + this.instance.registerEventCallback('keyboard-enable', () => { + this.transmitKeys = true; + }); + + // This avoid having continuously pressed keys because of alt+tab or any other command that blur from tab + window.addEventListener('blur', () => { + this.currentlyPressedKeys.forEach((value) => { + const text = ''; + const json = { + type: 'KEYBOARD_RELEASE', + keychar: text, + keycode: value, + }; + this.instance.sendEvent(json); + }); + this.currentlyPressedKeys.clear(); + }); + } + + /** + * Called when the user press a writable key (A-Z + 0-9 + symbols), send event to instance. + * + * @param {Event} event Event. + */ + onKeyPress(event) { + if (!this.transmitKeys) { + return; + } + const key = event.charCode; + let text = event.key || String.fromCharCode(key); + if (text === 'Spacebar') { + text = ' '; + } + let json = { + type: 'KEYBOARD_PRESS', + keychar: text, + keycode: key, + }; + this.instance.sendEvent(json); + json = { + type: 'KEYBOARD_RELEASE', + keychar: text, + keycode: key, + }; + this.instance.sendEvent(json); + } + + /** + * Called when the user press a key. Handle special events like backspace. + * + * @param {Event} event Event. + * @return {boolean} Whether or not the event must continue propagation. + */ + onKeyDown(event) { + if (!this.transmitKeys) { + return true; + } + + let key; + /** + * Convert invisible key or shortcut keys when ctrl/meta are pressed + * to Qt keycode in Base-16. + * We only handle shortcut keys (c,x,v) up when ctrl or meta are pressed: + * for OSX, onKeyUp() is never fired when meta is pressed so we need to emulate it. + */ + if (CTRL_SHORTCUT_KEYS[event.keyCode] && event.ctrlKey) { + key = parseInt(CTRL_SHORTCUT_KEYS[event.keyCode], 16); + } else if (CTRL_SHORTCUT_KEYS[event.keyCode] && event.metaKey) { + key = parseInt(CTRL_SHORTCUT_KEYS[event.keyCode], 16); + let json = { + type: 'KEYBOARD_PRESS', + keychar: '', + keycode: key, + }; + this.instance.sendEvent(json); + json = { + type: 'KEYBOARD_RELEASE', + keychar: '', + keycode: key, + }; + this.instance.sendEvent(json); + // No need to propagate event or the character will also be send + event.preventDefault(); + event.stopPropagation(); + event.returnValue = false; + return false; + } else if (INVISIBLE_KEYS[event.keyCode]) { + key = parseInt(INVISIBLE_KEYS[event.keyCode], 16); + } else { + return true; + } + + const json = { + type: 'KEYBOARD_PRESS', + keychar: '', + keycode: key, + }; + this.instance.sendEvent(json); + this.currentlyPressedKeys.set(key, key); + event.preventDefault(); + event.stopPropagation(); + event.returnValue = false; + return false; + } + + /** + * Called when the user release a key. Handle special events like backspace + * + * @param {Event} event Event. + * @return {boolean} Whether or not the event must continue propagation. + */ + onKeyUp(event) { + if (!this.transmitKeys) { + return true; + } + + let key; + /** + * Convert invisible key or shortcut keys when ctrl/meta are pressed + * to Qt keycode in Base-16. + * We only handle shortcut keys (c,x,v) up when ctrl is pressed: + * for OSX, onKeyUp() is never fired when meta is pressed so no need + * to handle the case here since we emulate a down up in onKeyDown() in this case. + */ + if (CTRL_SHORTCUT_KEYS[event.keyCode] && event.ctrlKey) { + key = parseInt(CTRL_SHORTCUT_KEYS[event.keyCode], 16); + } else if (INVISIBLE_KEYS[event.keyCode]) { + key = parseInt(INVISIBLE_KEYS[event.keyCode], 16); + } else { + return true; + } + + const json = { + type: 'KEYBOARD_RELEASE', + keychar: '', + keycode: key, + }; + this.instance.sendEvent(json); + this.currentlyPressedKeys.delete(key); + event.preventDefault(); + event.stopPropagation(); + event.returnValue = false; + return false; + } + + /** + * Bind all event listener callback. + */ + addKeyboardCallbacks() { + this.instance.root.tabIndex = 0; + + if (!this.isListenerAdded) { + this.instance.root.addEventListener('keypress', this.onKeyPress.bind(this)); + this.instance.root.addEventListener('keydown', this.onKeyDown.bind(this)); + this.instance.root.addEventListener('keyup', this.onKeyUp.bind(this)); + this.instance.root.focus(); + this.isListenerAdded = true; + } + } +}; diff --git a/src/plugins/MouseEvents.js b/src/plugins/MouseEvents.js new file mode 100644 index 0000000..350cdd6 --- /dev/null +++ b/src/plugins/MouseEvents.js @@ -0,0 +1,163 @@ +'use strict'; + +/** + * Instance mouse plugin. + * Forward touch events to instance. + */ +module.exports = class MouseEvents { + /** + * Plugin initialization. + * + * @param {Object} instance Associated instance. + */ + constructor(instance) { + // Reference instance + this.instance = instance; + + // Register plugin + this.instance.mouseEvents = this; + this.instance.mouseEventsEnabled = true; + + this.leftButtonPressed = false; + this.boundEventListener = this.releaseAtPreviousPositionEvent.bind(this); + } + + /** + * Mouse press event handler. + * + * @param {Event} event Event. + */ + onMousePressEvent(event) { + this.instance.video.muted = false; + if (event.button !== 0) { + return; + } + + event.preventDefault(); + event.stopPropagation(); + this.leftButtonPressed = true; + this.instance.x = this.instance.coordinateUtils.getXCoordinate(event); + this.instance.y = this.instance.coordinateUtils.getYCoordinate(event); + + let json = ''; + if (event.ctrlKey || event.metaKey) { + json = { + type: 'FAKE_MULTI_TOUCH_PRESS', + mode: event.shiftKey ? 2 : 1, x: this.instance.x, y: this.instance.y, + }; + } else { + json = {type: 'MOUSE_PRESS', x: this.instance.x, y: this.instance.y}; + } + this.instance.sendEvent(json); + + document.addEventListener('mouseup', this.boundEventListener, false); + } + + /** + * Mouse release event handler. + * + * @param {Event} event Event. + */ + onMouseReleaseEvent(event) { + if (event.button !== 0) { + return; + } + + event.preventDefault(); + event.stopPropagation(); + this.leftButtonPressed = false; + this.instance.x = this.instance.coordinateUtils.getXCoordinate(event); + this.instance.y = this.instance.coordinateUtils.getYCoordinate(event); + let json = ''; + if (event.ctrlKey || event.metaKey) { + json = { + type: 'FAKE_MULTI_TOUCH_RELEASE', + mode: event.shiftKey ? 2 : 1, x: this.instance.x, y: this.instance.y, + }; + } else { + json = {type: 'MOUSE_RELEASE', x: this.instance.x, y: this.instance.y}; + } + this.instance.sendEvent(json); + + document.removeEventListener('mouseup', this.boundEventListener, false); + } + + /** + * External mouse release event classback. + * Called when onmouseup event occurs outside of the player. + * + * @param {Event} event Event. + */ + releaseAtPreviousPositionEvent(event) { + if (event.button !== 0) { + return; + } + + event.preventDefault(); + event.stopPropagation(); + this.leftButtonPressed = false; + const json = { + type: event.ctrlKey || event.metaKey ? 'FAKE_MULTI_TOUCH_RELEASE' : 'MOUSE_RELEASE', + x: this.instance.x, + y: this.instance.y, + }; + this.instance.sendEvent(json); + + document.removeEventListener('mouseup', this.boundEventListener, false); + } + + /** + * Mouse move event handler. + * + * @param {Event} event Event. + */ + onMouseMoveEvent(event) { + if (!this.leftButtonPressed) { + return; + } + + event.preventDefault(); + event.stopPropagation(); + this.instance.x = this.instance.coordinateUtils.getXCoordinate(event); + this.instance.y = this.instance.coordinateUtils.getYCoordinate(event); + const json = {type: 'MOUSE_MOVE', x: this.instance.x, y: this.instance.y}; + this.instance.sendEvent(json); + } + + /** + * Mouse move event handler. + * + * @param {Event} event Event. + */ + onMouseWheelEvent(event) { + event.preventDefault(); + event.stopPropagation(); + this.instance.x = this.instance.coordinateUtils.getXCoordinate(event); + this.instance.y = this.instance.coordinateUtils.getYCoordinate(event); + const delta = event.wheelDelta; + const json = {type: 'WHEEL', x: this.instance.x, y: this.instance.y, delta: delta}; + this.instance.sendEvent(json); + } + + /** + * Method called when context menu try to open. + * + * @param {Event} event Event. + */ + cancelContextMenu(event) { + event.preventDefault(); + event.stopPropagation(); + event.returnValue = false; + } + + /** + * Bind all event handlers to the video wrapper. + */ + addMouseCallbacks() { + this.instance.videoWrapper.addEventListener('mousedown', this.onMousePressEvent.bind(this), false); + this.instance.videoWrapper.addEventListener('mouseup', this.onMouseReleaseEvent.bind(this), false); + this.instance.videoWrapper.addEventListener('mousemove', this.onMouseMoveEvent.bind(this), false); + this.instance.videoWrapper.addEventListener('mousewheel', this.onMouseWheelEvent.bind(this), false); + this.instance.videoWrapper.addEventListener('contextmenu', this.cancelContextMenu.bind(this), false); + } +}; diff --git a/src/plugins/MultiTouchEvents.js b/src/plugins/MultiTouchEvents.js new file mode 100644 index 0000000..a4605bd --- /dev/null +++ b/src/plugins/MultiTouchEvents.js @@ -0,0 +1,93 @@ +'use strict'; + +/** + * Instance multi touch plugin. + * Forward multi touch events to instance. + */ +module.exports = class MultiTouchEvents { + /** + * Plugin initialization. + * + * @param {Object} instance Associated instance. + */ + constructor(instance) { + // Reference instance + this.instance = instance; + + // Register plugin + this.instance.touchEvents = this; + this.instance.touchEventsEnabled = true; + } + + /** + * Called when the user starts touching the screen + * + * @param {Event} event Event. + */ + onScreenTouchStart(event) { + event.preventDefault(); + event.stopPropagation(); + + const json = {type: 'MULTI_TOUCH', nb: event.targetTouches.length, mode: 0, points: []}; + for (let i = 0; i < event.targetTouches.length; i++) { + const touch = event.targetTouches[i]; + + this.instance.x = this.instance.coordinateUtils.getXCoordinate(touch); + this.instance.y = this.instance.coordinateUtils.getYCoordinate(touch); + + json.points.push({x: this.instance.x, y: this.instance.y}); + } + this.instance.sendEvent(json); + } + + /** + * Called when the user is moving on the screen. + * + * @param {Event} event Event. + */ + onScreenTouchMove(event) { + event.preventDefault(); + event.stopPropagation(); + + const json = {type: 'MULTI_TOUCH', nb: event.targetTouches.length, mode: 2, points: []}; + for (let i = 0; i < event.targetTouches.length; i++) { + const touch = event.targetTouches[i]; + + this.instance.x = this.instance.coordinateUtils.getXCoordinate(touch); + this.instance.y = this.instance.coordinateUtils.getYCoordinate(touch); + + json.points.push({x: this.instance.x, y: this.instance.y}); + } + this.instance.sendEvent(json); + } + + /** + * Called when the user stops touching the screen. + * + * @param {Event} event Event. + */ + onScreenTouchEnd(event) { + event.preventDefault(); + event.stopPropagation(); + + const json = {type: 'MULTI_TOUCH', nb: event.targetTouches.length, mode: 1, points: []}; + for (let i = 0; i < event.targetTouches.length; i++) { + const touch = event.targetTouches[i]; + + this.instance.x = this.instance.coordinateUtils.getXCoordinate(touch); + this.instance.y = this.instance.coordinateUtils.getYCoordinate(touch); + + json.points.push({x: this.instance.x, y: this.instance.y}); + } + this.instance.sendEvent(json); + } + + /** + * Bind all event handlers to the video wrapper. + */ + addTouchCallbacks() { + this.instance.videoWrapper.addEventListener('touchstart', this.onScreenTouchStart.bind(this), false); + this.instance.videoWrapper.addEventListener('touchend', this.onScreenTouchEnd.bind(this), false); + this.instance.videoWrapper.addEventListener('touchmove', this.onScreenTouchMove.bind(this), false); + } +}; diff --git a/src/plugins/Network.js b/src/plugins/Network.js new file mode 100644 index 0000000..a1c761b --- /dev/null +++ b/src/plugins/Network.js @@ -0,0 +1,475 @@ +'use strict'; + +const OverlayPlugin = require('./util/OverlayPlugin'); + +const PROFILES = require('./util/network-profiles'); + +/** + * Instance network plugin. + * Provides network I/O control. + */ +module.exports = class Network extends OverlayPlugin { + /** + * Plugin initialization. + * + * @param {Object} instance Associated instance. + * @param {Object} i18n Translations keys for the UI. + * @param {boolean} basebandEnabled Whether or not baseband control is enabled. + */ + constructor(instance, i18n, basebandEnabled) { + super(instance); + + // Reference instance + this.instance = instance; + + // Register plugin + this.instance.network = this; + this.i18n = i18n || {}; + + this.fields = {}; + + this.basebandEnabled = basebandEnabled; + + // Render components + this.renderToolbarButton(); + this.renderWidget(); + + // Listen for initial network + this.instance.registerEventCallback('NETWORK', this.setActive.bind(this)); + + /* + * Listen for network messages: + * state wifi up_rate:: + * down_rate:: + * up_delay:: + * down_delay: + * up_pkt_loss:: + * down_pkt_loss:: + * dns_delay:: + */ + this.instance.registerEventCallback('network_profile', (message) => { + const values = message.split(' '); + if (values.length < 9) { + return; + } + const upSpeed = values[2].split(':'); + const downSpeed = values[3].split(':'); + const upDelay = values[4].split(':'); + const downDelay = values[5].split(':'); + const upPacketLoss = values[6].split(':'); + const downPacketLoss = values[7].split(':'); + const dnsDelay = values[8].split(':'); + + const isThrottlingEnabled = upSpeed[1] === 'enabled' + && downSpeed[1] === 'enabled' + && upDelay[1] === 'enabled' + && downDelay[1] === 'enabled' + && upPacketLoss[1] === 'enabled' + && downPacketLoss[1] === 'enabled' + && dnsDelay[1] === 'enabled'; + + const profile = PROFILES.find((elem) => { + return elem.downSpeed.value === parseFloat(downSpeed[2]) && + elem.downDelay.value === parseFloat(downDelay[2]) && + elem.downPacketLoss.value === parseFloat(downPacketLoss[2]) && + elem.upSpeed.value === parseFloat(upSpeed[2]) && + elem.upDelay.value === parseFloat(upDelay[2]) && + elem.upPacketLoss.value === parseFloat(upPacketLoss[2]) && + elem.dnsDelay.value === parseFloat(dnsDelay[2]); + }); + + if (profile && isThrottlingEnabled) { + this.select.value = profile.name; + } else { + this.select.value = this.i18n.NETWORK_DELECT_PROFILE || 'Select a profile'; + } + this.changeProfile(); + }); + + // Listen for baseband messages: " " + this.instance.registerEventCallback('baseband', (message) => { + const values = message.split(' '); + if (values.length < 3) { + return; + } + + if (values[0] === 'network' && values[1] === 'operator') { + this.networkOperatorMMC.value = values[2]; + } + if (values[0] === 'network' && values[1] === 'operator_name') { + this.networkOperatorName.value = values.slice(2).join(' '); + } + if (values[0] === 'sim' && values[1] === 'operator') { + this.simOperatorMMC.value = values[2]; + } + if (values[0] === 'sim' && values[1] === 'operator_name') { + this.simOperatorName.value = values.slice(2).join(' '); + } + if (values[0] === 'sim' && values[1] === 'imsi_id') { + this.simMSIN.value = values[2]; + } + if (values[0] === 'sim' && values[1] === 'phone_number') { + this.simOperatorPhoneNumber.value = values[2]; + } + }); + } + + /** + * Add the button to the player toolbar. + */ + renderToolbarButton() { + const toolbars = this.instance.getChildByClass(this.instance.root, 'gm-toolbar'); + if (!toolbars) { + return; // if we don't have toolbar, we can't spawn the widget + } + + const toolbar = toolbars.children[0]; + this.toolbarBtn = document.createElement('li'); + this.toolbarBtnImage = document.createElement('div'); + this.toolbarBtnImage.className = 'gm-icon-button gm-network-button'; + this.toolbarBtnImage.title = this.i18n.NETWORK_TITLE || 'Network & Baseband'; + this.toolbarBtn.appendChild(this.toolbarBtnImage); + this.toolbarBtn.onclick = this.toggleWidget.bind(this); + toolbar.appendChild(this.toolbarBtn); + } + + /** + * Render the widget. + */ + renderWidget() { + // Create elements + this.widget = document.createElement('div'); + this.form = document.createElement('form'); + + // Generate title + const title = document.createElement('div'); + title.className = 'gm-title'; + title.innerHTML = this.i18n.NETWORK_TITLE || 'Network & Baseband'; + this.form.appendChild(title); + + // Generate input rows + const inputs = document.createElement('div'); + inputs.className = 'gm-inputs'; + + // Create select + this.select = document.createElement('select'); + const defaultOption = new Option(this.i18n.NETWORK_DELECT_PROFILE || 'Select a profile'); + this.select.add(defaultOption); + this.select.onchange = this.changeProfile.bind(this); + inputs.appendChild(this.select); + + // Add option for each child + PROFILES.slice().reverse() + .forEach((profile) => { + const option = new Option(profile.label, profile.name); + this.select.add(option); + }); + + // Create detail section + this.profileDetails = document.createElement('div'); + this.profileDetails.className = 'gm-profile-details gm-hidden'; + + // Add detail fields + this.profileDetails.appendChild(this.createDetailsSection('Download speed', 'downSpeed')); + this.profileDetails.appendChild(this.createDetailsSection('Upload speed', 'upSpeed')); + this.profileDetails.appendChild(this.createDetailsSection('Download delay', 'downDelay')); + this.profileDetails.appendChild(this.createDetailsSection('Upload delay', 'upDelay')); + this.profileDetails.appendChild(this.createDetailsSection('Download packet loss', 'downPacketLoss')); + this.profileDetails.appendChild(this.createDetailsSection('Upload packet loss', 'upPacketLoss')); + this.profileDetails.appendChild(this.createDetailsSection('DNS Delay', 'dnsDelay')); + + if (this.basebandEnabled) { + this.networkOperator = document.createElement('div'); + + const networkOperatorLabelDiv = document.createElement('div'); + networkOperatorLabelDiv.className = 'gm-section'; + const networkOperatorLabel = document.createElement('label'); + networkOperatorLabel.innerHTML = this.i18n.NETWORK_OPERATOR || 'Network Operator'; + networkOperatorLabelDiv.appendChild(networkOperatorLabel); + + const networkOperatorMMCDiv = document.createElement('div'); + networkOperatorMMCDiv.className = 'gm-fields'; + const networkOperatorMMCLabel = document.createElement('label'); + networkOperatorMMCLabel.innerHTML = 'MCC/MNC'; + this.networkOperatorMMC = document.createElement('input'); + this.networkOperatorMMC.className = 'gm-network-network-mmc'; + this.networkOperatorMMC.placeholder = 'eg: 20814'; + this.networkOperatorMMC.pattern = '[0-9]{5,6}'; + this.networkOperatorMMC.title = 'Operator MCC/MNC'; + networkOperatorMMCDiv.appendChild(networkOperatorMMCLabel); + networkOperatorMMCDiv.appendChild(this.networkOperatorMMC); + + const networkOperatorNameDiv = document.createElement('div'); + networkOperatorNameDiv.className = 'gm-fields'; + const networkOperatorNameLabel = document.createElement('label'); + networkOperatorNameLabel.innerHTML = 'Name'; + this.networkOperatorName = document.createElement('input'); + this.networkOperatorName.className = 'gm-network-network-name'; + this.networkOperatorName.placeholder = 'eg: Verizon'; + this.networkOperatorName.title = 'Operator Name'; + networkOperatorNameDiv.appendChild(networkOperatorNameLabel); + networkOperatorNameDiv.appendChild(this.networkOperatorName); + + this.networkOperator.appendChild(networkOperatorLabelDiv); + this.networkOperator.appendChild(networkOperatorMMCDiv); + this.networkOperator.appendChild(networkOperatorNameDiv); + + this.simOperator = document.createElement('div'); + + const simperatorLabelDiv = document.createElement('div'); + simperatorLabelDiv.className = 'gm-section'; + const simperatorLabel = document.createElement('label'); + simperatorLabel.innerHTML = this.i18n.NETWORK_SIM_OPERATOR || 'SIM Operator'; + simperatorLabelDiv.appendChild(simperatorLabel); + + const simOperatorMMCDiv = document.createElement('div'); + simOperatorMMCDiv.className = 'gm-fields'; + const simOperatorMMCLabel = document.createElement('label'); + simOperatorMMCLabel.innerHTML = 'MCC/MNC'; + this.simOperatorMMC = document.createElement('input'); + this.simOperatorMMC.className = 'gm-network-sim-mmc'; + this.simOperatorMMC.placeholder = 'eg: 20814'; + this.simOperatorMMC.pattern = '[0-9]{5,6}'; + this.simOperatorMMC.title = 'SIM Operator MCC/MNC'; + this.simOperatorMMC.addEventListener('keyup', this.checkSimImsiErrors.bind(this)); + simOperatorMMCDiv.appendChild(simOperatorMMCLabel); + simOperatorMMCDiv.appendChild(this.simOperatorMMC); + + const simOperatorNameDiv = document.createElement('div'); + simOperatorNameDiv.className = 'gm-fields'; + const simOperatorNameLabel = document.createElement('label'); + simOperatorNameLabel.innerHTML = 'Name'; + this.simOperatorName = document.createElement('input'); + this.simOperatorName.className = 'gm-network-sim-name'; + this.simOperatorName.placeholder = 'eg: AT&T'; + this.simOperatorName.title = 'SIM Operator Name'; + simOperatorNameDiv.appendChild(simOperatorNameLabel); + simOperatorNameDiv.appendChild(this.simOperatorName); + + const simMSINDiv = document.createElement('div'); + simMSINDiv.className = 'gm-fields'; + const simMSINLabel = document.createElement('label'); + simMSINLabel.innerHTML = 'MSIN'; + this.simMSIN = document.createElement('input'); + this.simMSIN.className = 'gm-network-sim-msin'; + this.simMSIN.placeholder = 'eg: 2176510739'; + this.simMSIN.pattern = '[0-9]{9,10}'; + this.simMSIN.title = 'SIM MSIN'; + this.simMSIN.addEventListener('keyup', this.checkSimImsiErrors.bind(this)); + simMSINDiv.appendChild(simMSINLabel); + simMSINDiv.appendChild(this.simMSIN); + + const simOperatorPhoneDiv = document.createElement('div'); + simOperatorPhoneDiv.className = 'gm-fields'; + const simOperatorPhoneLabel = document.createElement('label'); + simOperatorPhoneLabel.innerHTML = 'Phone Number'; + this.simOperatorPhoneNumber = document.createElement('input'); + this.simOperatorPhoneNumber.className = 'gm-network-sim-phone'; + this.simOperatorPhoneNumber.placeholder = 'eg: 8004337300'; + this.simOperatorPhoneNumber.pattern = '[0-9]*'; + this.simOperatorPhoneNumber.title = 'Phone Number'; + simOperatorPhoneDiv.appendChild(simOperatorPhoneLabel); + simOperatorPhoneDiv.appendChild(this.simOperatorPhoneNumber); + + this.simOperator.appendChild(simperatorLabelDiv); + this.simOperator.appendChild(simOperatorMMCDiv); + this.simOperator.appendChild(simMSINDiv); + this.simOperator.appendChild(simOperatorNameDiv); + this.simOperator.appendChild(simOperatorPhoneDiv); + } + + // Add submit button + this.submitBtn = document.createElement('button'); + this.submitBtn.className = 'gm-network-update'; + this.submitBtn.innerHTML = this.i18n.NETWORK_UPDATE || 'Update'; + this.submitBtn.onclick = this.sendDataToInstance.bind(this); + + // Setup + this.form.appendChild(inputs); + this.form.appendChild(this.profileDetails); + if (this.basebandEnabled) { + this.form.appendChild(this.networkOperator); + this.form.appendChild(this.simOperator); + } + this.form.appendChild(this.submitBtn); + + this.widget.className = 'gm-overlay gm-network-plugin gm-hidden'; + + // Add close button + const close = document.createElement('div'); + close.className = 'gm-close-btn'; + close.onclick = this.toggleWidget.bind(this); + + this.widget.appendChild(close); + this.widget.appendChild(this.form); + + // Render into document + this.overlays.push(this.widget); + this.instance.root.appendChild(this.widget); + } + + /** + * Display or hide the widget. + */ + toggleWidget() { + // Notify other callers + if (this.widget.classList.contains('gm-hidden')) { + this.instance.emit('close-overlays'); + this.instance.emit('keyboard-disable'); + } else { + this.instance.emit('keyboard-enable'); + } + + // Toggle display + this.widget.classList.toggle('gm-hidden'); + this.toolbarBtnImage.classList.toggle('gm-active'); + } + + /** + * MSIN verification according to MCC/MNC length: + * - MCC/MNC is 5 digits => MSIN should be 10 digits + * - MCC/MNC is 6 digits => MSIN should be 9 digits + * Only do the check if both are not empty: we might set one and not the other + * (We can't handle the case where one was set previously and the other is now + * beeing configured.) + */ + checkSimImsiErrors() { + this.simMSIN.setCustomValidity(''); + if (this.simOperatorMMC.value.length > 0 && this.simMSIN.value.length > 0) { + if (this.simOperatorMMC.value.length === 6 && this.simMSIN.value.length !== 9) { + this.simMSIN.setCustomValidity('Should be 9'); + } else if (this.simOperatorMMC.value.length === 5 && this.simMSIN.value.length !== 10) { + this.simMSIN.setCustomValidity('Should be 10'); + } + } + } + + /** + * Send information to instance. + * + * @param {Event} event Event. + */ + sendDataToInstance(event) { + event.preventDefault(); + + if (!this.form.checkValidity()) { + return; + } + + const profile = PROFILES.find((elem) => elem.name === this.select.value); + if (profile) { + const msgs = []; + if (profile.id === 0) { + msgs.push('disable wifi all'); + } else { + msgs.push('enable wifi all'); + msgs.push('set wifi up_rate ' + profile.upSpeed.value); + msgs.push('set wifi down_rate ' + profile.downSpeed.value); + msgs.push('set wifi up_delay ' + profile.upDelay.value); + msgs.push('set wifi down_delay ' + profile.downDelay.value); + msgs.push('set wifi up_pkt_loss ' + profile.upPacketLoss.value); + msgs.push('set wifi down_pkt_loss ' + profile.downPacketLoss.value); + msgs.push('set wifi dns_delay ' + profile.dnsDelay.value); + } + const json = {channel: 'network_profile', messages: msgs}; + this.instance.sendEvent(json); + } + + const msgs = []; + if (this.basebandEnabled) { + if (this.networkOperatorMMC.value) { + msgs.push('network operator ' + this.networkOperatorMMC.value); + } + if (this.networkOperatorName.value) { + msgs.push('network operator_name ' + this.networkOperatorName.value); + } + + if (this.simOperatorMMC.value) { + msgs.push('sim operator ' + this.simOperatorMMC.value); + } + + if (this.simOperatorName.value) { + msgs.push('sim operator_name ' + this.simOperatorName.value); + } + + if (this.simMSIN.value) { + msgs.push('sim imsi_id ' + this.simMSIN.value); + } + + if (this.simOperatorPhoneNumber.value) { + msgs.push('sim phone_number ' + this.simOperatorPhoneNumber.value); + } + + if (msgs.length > 0) { + const json = {channel: 'baseband', messages: msgs}; + this.instance.sendEvent(json); + } + } + + this.toggleWidget(); + } + + /** + * Update form according to the selected profile. + */ + changeProfile() { + const profile = PROFILES.find((elem) => elem.name === this.select.value); + if (profile) { + this.loadDetails(profile); + this.profileDetails.classList.remove('gm-hidden'); + } else { + this.profileDetails.classList.add('gm-hidden'); + } + } + + /** + * Creates and return the widget "details" section. + * + * @param {string} label Section label. + * @param {string} type Section type. + * @return {HTMLElement} Details section + */ + createDetailsSection(label, type) { + const section = document.createElement('section'); + this.fields[type] = document.createElement('span'); + section.innerHTML = label + ': '; + section.appendChild(this.fields[type]); + + return section; + } + + /** + * Update UI according to the given profile. + * + * @param {Object} profile Profile to load. + */ + loadDetails(profile) { + Object.entries(profile).forEach(([field, val]) => { + if (field === 'label' || field === 'name' || field === 'id') { + return; + } + this.fields[field].innerHTML = val.label; + }); + } + + /** + * Update UI according to the current active profile. + * + * @param {string} id Profile id. + */ + setActive(id) { + const profile = PROFILES.find((elem) => elem.id === Number(id)); + if (!profile || !String(id).length) { + return; + } + + const options = this.select.getElementsByTagName('option'); + for (let i = 0; i < options.length; i++) { + const option = options[i]; + if (option.value === profile.name) { + option.selected = 'selected'; + } + } + this.changeProfile(); + } +}; diff --git a/src/plugins/PeerConnectionStats.js b/src/plugins/PeerConnectionStats.js new file mode 100644 index 0000000..309d0b9 --- /dev/null +++ b/src/plugins/PeerConnectionStats.js @@ -0,0 +1,110 @@ +'use strict'; + +/** + * Instance peer connections plugin. + * Provides peer connections statistics. + */ +module.exports = class PeerConnectionStats { + /** + * Plugin initialization. + * + * @param {Object} instance Associated instance. + * @param {RTCPeerConnection} connection WebRTC connection. + * @param {number} interval Stats update interval in ms. + */ + constructor(instance, connection, interval) { + // Reference instance + this.instance = instance; + + // Register plugin + this.instance.peerConnectionStats = this; + + this.connection = connection; + + setTimeout(() => { + this.connection.getStats(null).then((stats) => { + stats.forEach((entry) => { + if (entry.kind === 'video') { + if (entry.type === 'inbound-rtp') { + const codec = stats.get(entry.codecId); + if (codec) { + this.logAndBroadcast('codec', codec.mimeType); + } + } + if (entry.type === 'track') { + this.logAndBroadcast('width', entry.frameWidth); + this.logAndBroadcast('height', entry.frameHeight); + this.logAndBroadcast('jitter', Math.round( + entry.jitterBufferDelay / entry.jitterBufferEmittedCount * 1000 + )); + } + } + if (entry.type === 'candidate-pair' && entry.state === 'succeeded') { + this.logAndBroadcast('rtt', entry.currentRoundTripTime * 1000); + const candidate = stats.get(entry.localCandidateId); + this.hideDefaultTurnWarning(); + if (candidate && candidate.candidateType === 'relay') { + this.logAndBroadcast('turn', true); + if (this.instance.options.turn.default) { + this.logAndBroadcast('default', true); + this.displayDefaultTurnWarning(); + } else { + this.logAndBroadcast('default', false); + } + } else { + this.logAndBroadcast('turn', false); + } + } + }); + }); + }, interval); + } + + /** + * Format & send a stats event. + * + * @param {string} type Event name. + * @param {string} value Stat value. + */ + logAndBroadcast(type, value) { + this.instance.dispatchEvent(type, {msg: value}); + } + + /** + * Creates & display the default turn warning. + */ + displayDefaultTurnWarning() { + let message = '

Using a default TURN

Performance is not optimal.'; + const warning = document.createElement('a'); + warning.classList.add('gm-default-turn-button'); + warning.classList.add('gm-icon-button'); + const hover = document.createElement('div'); + hover.className = 'gm-default-turn-used gm-hidden'; + if (this.instance.options.connectionFailedURL) { + message = message + '
Click on the icon to learn more.'; + warning.href = this.instance.options.connectionFailedURL; + warning.target = '_blank'; + } + hover.innerHTML = message; + warning.appendChild(hover); + + warning.onmouseenter = () => { + hover.classList.remove('gm-hidden'); + }; + warning.onmouseleave = () => { + hover.classList.add('gm-hidden'); + }; + const toolbar = this.instance.getChildByClass(this.instance.root, 'gm-toolbar'); + toolbar.appendChild(warning); + } + + /** + * Hide the default turn warning. + */ + hideDefaultTurnWarning() { + const element = this.instance.getChildByClass(this.instance.root, 'gm-default-turn-button'); + if (element) { + element.remove(); + } + } +}; diff --git a/src/plugins/Phone.js b/src/plugins/Phone.js new file mode 100644 index 0000000..6b4acf7 --- /dev/null +++ b/src/plugins/Phone.js @@ -0,0 +1,222 @@ +'use strict'; + +const OverlayPlugin = require('./util/OverlayPlugin'); + +/** + * Instance phone plugin. + * Provides phone call and SMS support. + */ +module.exports = class Phone extends OverlayPlugin { + /** + * Plugin initialization. + * + * @param {Object} instance Associated instance. + * @param {Object} i18n Translations keys for the UI. + */ + constructor(instance, i18n) { + super(instance); + + // Reference instance + this.instance = instance; + this.i18n = i18n || {}; + + // Register plugin + this.instance.phone = this; + + // Render components + this.renderToolbarButton(); + this.renderWidget(); + } + + /** + * Add the button to the player toolbar. + */ + renderToolbarButton() { + const toolbars = this.instance.getChildByClass(this.instance.root, 'gm-toolbar'); + if (!toolbars) { + return; // if we don't have toolbar, we can't spawn the widget + } + + const toolbar = toolbars.children[0]; + this.toolbarBtn = document.createElement('li'); + this.toolbarBtnImage = document.createElement('div'); + this.toolbarBtnImage.className = 'gm-icon-button gm-phone-button'; + this.toolbarBtnImage.title = this.i18n.PHONE_TITLE || 'Phone'; + this.toolbarBtn.appendChild(this.toolbarBtnImage); + this.toolbarBtn.onclick = this.toggleWidget.bind(this); + toolbar.appendChild(this.toolbarBtn); + } + + /** + * Render the widget. + */ + renderWidget() { + // Create elements + this.widget = document.createElement('div'); + this.container = document.createElement('div'); + + // Generate title + const title = document.createElement('div'); + title.className = 'gm-title'; + title.innerHTML = this.i18n.PHONE_TITLE || 'Phone'; + this.container.appendChild(title); + + // Generate input rows + const inputs = document.createElement('div'); + inputs.className = 'gm-inputs'; + + // Phone group + const phoneGroup = document.createElement('div'); + this.phoneInput = document.createElement('input'); + this.phoneBtn = document.createElement('button'); + this.phoneInput.type = 'text'; + this.phoneInput.className = 'gm-phone-number'; + this.phoneInput.placeholder = this.i18n.PHONE_CALL_PLACEHOLDER || 'Please enter the phone number'; + this.phoneInput.addEventListener('keyup', this.validate.bind(this)); + this.phoneBtn.className = 'gm-phone-call'; + this.phoneBtn.innerHTML = this.i18n.PHONE_CALL || 'Call'; + this.phoneBtn.onclick = this.sendPhoneCallToInstance.bind(this); + this.phoneBtn.disabled = true; + + const incomingPhoneLabel = this.i18n.PHONE_INCOMING || 'Incoming phone number'; + + phoneGroup.innerHTML = ''; + phoneGroup.className = 'gm-phone-group'; + phoneGroup.appendChild(this.phoneInput); + phoneGroup.appendChild(this.phoneBtn); + inputs.appendChild(phoneGroup); + + // Text group + const textGroup = document.createElement('div'); + this.textInput = document.createElement('textarea'); + this.textBtn = document.createElement('button'); + this.textInput.className = 'gm-phone-message'; + this.textInput.placeholder = this.i18n.PHONE_MESSAGE_PLACEHOLDER || 'Please enter the incoming message'; + this.textInput.rows = 5; + this.textInput.addEventListener('keyup', this.validate.bind(this)); + this.textBtn.className = 'gm-phone-send'; + this.textBtn.innerHTML = this.i18n.PHONE_MESSAGE || 'Send message'; + this.textBtn.onclick = this.sendSMSToInstance.bind(this); + this.textBtn.disabled = true; + + const messageLabel = this.i18n.PHONE_MESSAGE_VALUE || 'Message'; + textGroup.innerHTML = ''; + textGroup.className = 'gm-phone-group'; + textGroup.appendChild(this.textInput); + textGroup.appendChild(this.textBtn); + inputs.appendChild(textGroup); + + this.container.appendChild(inputs); + + // Setup + this.widget.className = 'gm-overlay gm-phone-plugin gm-hidden'; + + // Add close button + const close = document.createElement('div'); + close.className = 'gm-close-btn'; + close.onclick = this.toggleWidget.bind(this); + + this.widget.appendChild(close); + this.widget.appendChild(this.container); + + // Render into document + this.overlays.push(this.widget); + this.instance.root.appendChild(this.widget); + } + + /** + * Display or hide the widget. + */ + toggleWidget() { + // Notify other callers + if (this.widget.classList.contains('gm-hidden')) { + this.instance.emit('close-overlays'); + this.instance.emit('keyboard-disable'); + } else { + this.instance.emit('keyboard-enable'); + } + + // Toggle display + this.widget.classList.toggle('gm-hidden'); + this.toolbarBtnImage.classList.toggle('gm-active'); + } + + /** + * Validate phone number format. + * + * @return {boolean} Whether or not phone number format is valid. + */ + validatePhoneNumber() { + const phoneRegex = /^(\+[0-9]{1,14}|[0-9]{1,16})$/g; + return this.phoneInput.value.match(phoneRegex); + } + + /** + * Send phone call event to the instance. + * + * @param {Event} event Event. + */ + sendPhoneCallToInstance(event) { + if (event) { + event.preventDefault(); + } + + if (!this.validatePhoneNumber()) { + return; + } + + const json = {channel: 'baseband', messages: [ + 'gsm call ' + this.phoneInput.value + ]}; + this.instance.sendEvent(json); + this.toggleWidget(); + } + + /** + * Validate SMS text format. + * + * @return {boolean} Whether or not SMS text format is valid. + */ + validateSMSText() { + return this.textInput.value.length > 0; + } + + /** + * Send SMS event to the instance. + * + * @param {Event} event Event. + */ + sendSMSToInstance(event) { + if (event) { + event.preventDefault(); + } + + if (!this.validatePhoneNumber() || !this.validateSMSText()) { + return; + } + + const json = { + channel: 'baseband', messages: [ + 'sms send ' + this.phoneInput.value + ' ' + this.textInput.value + ] + }; + this.instance.sendEvent(json); + this.toggleWidget(); + } + + /** + * Validate all widget inputs. + * + * @return {boolean} Whether or not inputs are valid. + */ + validate() { + const phoneIsValid = this.validatePhoneNumber(); + const textIsValid = this.validateSMSText(); + const valid = textIsValid && phoneIsValid; + + this.phoneBtn.disabled = !phoneIsValid; + this.textBtn.disabled = !valid; + + return valid; + } +}; diff --git a/src/plugins/Screencast.js b/src/plugins/Screencast.js new file mode 100644 index 0000000..be233ea --- /dev/null +++ b/src/plugins/Screencast.js @@ -0,0 +1,376 @@ +'use strict'; + +const OverlayPlugin = require('./util/OverlayPlugin'); + +const log = require('loglevel'); +log.setDefaultLevel('debug'); + +const MAX_SCREENCAST_LENGTH_IN_MINUTES = 3; +const CAPTURE_INTERVAL_MS = 50; + +/** + * Instance screencast plugin. + * Provides screenshot and video capture. + */ +module.exports = class Screencast extends OverlayPlugin { + /** + * Plugin initialization. + * + * @param {Object} instance Associated instance. + * @param {Object} i18n Translations keys for the UI. + */ + constructor(instance, i18n) { + super(instance); + + // Reference instance + this.instance = instance; + this.i18n = i18n || {}; + + // Register plugin + this.instance.screencast = this; + + // Render components + this.renderToolbarButton(); + this.renderWidget(); + + // Screencast webrtc stuff + this.recordedBlobs = []; + this.mediaRecorder = null; + this.isRecording = false; + this.startTime = 0; + this.displayInterval = null; + } + + /** + * MediaRecorder recorded data available callback. + * + * @param {Event} event Event. + */ + handleDataAvailable(event) { + if (event.data && event.data.size > 0) { + this.recordedBlobs.push(event.data); + } + } + + /** + * Get file extension for a given MIME type. + * + * @param {string} mime MIME type. + * @return {string} File extention + */ + getExtensionFromMimeType(mime) { + const types = { + 'video/x-msvideo': '.avi', + 'video/mpeg': '.mpeg', + 'video/ogg': '.ogv', + 'video/webm': '.webm', + 'video/3gpp': '.3gp', + 'video/3gpp2': '.3g2', + 'video/mp4': '.mp4', + 'video/x-matroska': '.mkv', + 'video/x-flv': '.f4v' + }; + + let extension = types[mime.toLowerCase()]; + if (!extension) { + log.warn('Unknown MIME type: ', mime); + extension = '.webm'; + } + return extension; + } + + /** + * Download recorded screencast. + */ + downloadScreencast() { + const blob = new Blob(this.recordedBlobs, {type: this.mediaRecorder.mimeType}); + const url = window.URL.createObjectURL(blob); + const a = document.createElement('a'); + a.style.display = 'none'; + a.href = url; + a.download = 'genymotion' + this.getExtensionFromMimeType(this.mediaRecorder.mimeType); + document.body.appendChild(a); + a.click(); + setTimeout(() => { + document.body.removeChild(a); + window.URL.revokeObjectURL(url); + }, 100); + this.isRecording = false; + } + + /** + * Update UI based on MediaRecorder availability. + */ + checkForMediarecorder() { + if (typeof MediaRecorder === 'undefined') { + this.screencast.classList.add('disabled'); + this.screencastBtn.title = this.i18n.SCREENCAST_NOMEDIARECORDER_TOOLTIP || 'Screencast not supported'; + } + } + + /** + * Display screencast timer indicator. + */ + displayTimer() { + if (this.timer.classList.contains('gm-timer-hidden')) { + this.timer.classList.remove('gm-timer-hidden'); + this.displayInterval = setInterval(this.displayTimer.bind(this), 1000); + } + + const endTime = new Date(); + + // compute seconds + let timeDiff = endTime - this.startTime; + timeDiff /= 1000; + const seconds = Math.round(timeDiff % 60); + + // compute minutes + timeDiff = Math.floor(timeDiff / 60); + const minutes = Math.round(timeDiff % 60); + + this.timer.innerHTML = ('0' + minutes).slice(-2) + ':' + ('0' + seconds).slice(-2); + + // if the screencast is 3min long, we stop it + if (minutes === MAX_SCREENCAST_LENGTH_IN_MINUTES) { + this.stopRecording(); + } + } + + /** + * Hide screencast timer indicator. + */ + hideTimer() { + clearInterval(this.displayInterval); + this.timer.classList.add('gm-timer-hidden'); + this.timer.innerHTML = ''; + } + + findBestMimeType() { + const supportedMimeTypes = []; + [ + 'video/webm', + 'video/x-matroska', + 'video/mpeg', + 'video/ogg', + 'video/3gpp', + 'video/3gpp2', + 'video/mp4', + 'video/x-flv' + + ].forEach((mimeType) => { + if (MediaRecorder.isTypeSupported(mimeType)) { + supportedMimeTypes.push(mimeType); + } + }); + + return supportedMimeTypes[0]; + } + + /** + * Start screencast recording. + */ + startRecording() { + try { + this.mediaRecorder = new MediaRecorder(this.instance.stream, { + mimeType: this.findBestMimeType(), + }); + } catch (error) { + log.error('Error while creating MediaRecorder: ' + error); + this.hideTimer(); + this.toolbarBtnImage.classList.remove('gm-screencast-button-recording'); + return; + } + + this.recordedBlobs = []; + this.isRecording = true; + this.startTime = new Date(); + this.displayTimer(); + this.mediaRecorder.ondataavailable = this.handleDataAvailable.bind(this); + this.mediaRecorder.start(CAPTURE_INTERVAL_MS); + log.debug('MediaRecorder started', this.mediaRecorder); + } + + /** + * Stop screencast recording. + */ + stopRecording() { + this.mediaRecorder.stop(); + this.hideTimer(); + this.toolbarBtnImage.classList.remove('gm-screencast-button-recording'); + this.downloadScreencast(); + log.debug('MediaRecorder stopped', this.mediaRecorder); + } + + /** + * Add the button to the player toolbar. + */ + renderToolbarButton() { + const toolbars = this.instance.getChildByClass(this.instance.root, 'gm-toolbar'); + if (!toolbars) { + return; // if we don't have toolbar, we can't spawn the widget + } + + const toolbar = toolbars.children[0]; + this.toolbarBtn = document.createElement('li'); + this.toolbarBtnImage = document.createElement('div'); + this.toolbarBtnImage.className = 'gm-icon-button gm-screencast-button'; + this.toolbarBtnImage.title = this.i18n.SCREENCAST_TITLE || 'Screencast'; + this.timer = document.createElement('div'); + this.timer.className = 'gm-screencast-timer gm-timer-hidden'; + this.toolbarBtnImage.appendChild(this.timer); + this.toolbarBtn.appendChild(this.toolbarBtnImage); + this.toolbarBtn.onclick = this.toggleWidget.bind(this); + toolbar.appendChild(this.toolbarBtn); + } + + /** + * Render the widget. + */ + renderWidget() { + // Create elements + this.widget = document.createElement('div'); + this.form = document.createElement('form'); + + // Generate title + const title = document.createElement('div'); + title.className = 'gm-title'; + title.innerHTML = this.i18n.SCREENCAST_TITLE || 'Screencast'; + this.form.appendChild(title); + + // Generate input rows + const inputs = document.createElement('div'); + inputs.className = 'gm-inputs'; + + const screenshot = document.createElement('div'); + this.screenshotBtn = document.createElement('div'); + this.screenshotBtn.className = 'gm-action gm-screencast-screenshot'; + screenshot.onclick = this.onScreenshotClick.bind(this); + screenshot.className = 'gm-horizontal gm-screenshot'; + + const screenshotLabel = this.i18n.SCREENCAST_SCREENSHOT || 'Screenshot'; + screenshot.innerHTML = ''; + + screenshot.appendChild(this.screenshotBtn); + inputs.appendChild(screenshot); + + this.screencast = document.createElement('div'); + this.screencastBtn = document.createElement('div'); + this.screencastBtn.className = 'gm-action gm-screencast-screencast'; + + this.screencast.onclick = this.onScreencastClick.bind(this); + this.screencast.className = 'gm-horizontal gm-screencast'; + + const screencastLabel = this.i18n.SCREENCAST_SCREENCAST || 'Screencast'; + this.screencast.innerHTML = ''; + + this.screencast.appendChild(this.screencastBtn); + inputs.appendChild(this.screencast); + + this.form.appendChild(inputs); + + // Setup + this.widget.className = 'gm-overlay gm-screencast-plugin gm-hidden'; + + // Add close button + const close = document.createElement('div'); + close.className = 'gm-close-btn'; + close.onclick = this.toggleWidget.bind(this); + + this.widget.appendChild(close); + this.widget.appendChild(this.form); + + // Render into document + this.overlays.push(this.widget); + this.instance.root.appendChild(this.widget); + } + + /** + * Display or hide the widget. + * + * @param {boolean} keepIconActive Whether to keep plugin button active or not. + */ + toggleWidget(keepIconActive) { + this.checkForMediarecorder(); + + // When we are recording, we don't open the widget + if (this.isRecording) { + this.stopRecording(); + return; + } + + // Notify other callers + if (this.widget.classList.contains('gm-hidden')) { + this.instance.emit('close-overlays'); + this.instance.emit('keyboard-disable'); + } else { + this.instance.emit('keyboard-enable'); + } + + // Toggle display + this.widget.classList.toggle('gm-hidden'); + this.toolbarBtnImage.classList.toggle('gm-active'); + + if (keepIconActive === true) { + this.toolbarBtnImage.classList.add('gm-screencast-button-recording'); + } + } + + /** + * Take a screenshot. + * + * @param {Event} event Event. + */ + onScreenshotClick(event) { + event.preventDefault(); + + this.toggleWidget(); + + // Setup + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + const {video} = this.instance; + + // Set canvas size to render to + canvas.width = video.videoWidth; + canvas.height = video.videoHeight; + + // Render into the canvas the current state of video + if (ctx && video instanceof HTMLVideoElement) { + ctx.drawImage(video, 0, 0, video.videoWidth, + video.videoHeight, 0, 0, video.videoWidth, video.videoHeight); + } else { + return; + } + + // configure download link + const downloadLink = document.createElement('a'); + downloadLink.download = 'genymotion-screenshot.png'; + document.body.appendChild(downloadLink); + + // Get canvas data / force download + let data = canvas.toDataURL('image/png'); + if (data) { + data = data.replace(/^data:image\/[^;]*/, 'data:application/octet-stream'); + } + downloadLink.href = data; + + // Trigger download + downloadLink.click(); + + setTimeout(() => { + document.body.removeChild(downloadLink); + }, 100); + } + + /** + * Toggle screencast recording. + */ + onScreencastClick() { + if (!this.isRecording) { + this.toggleWidget(true); + this.startRecording(); + } else { + this.stopRecording(); + } + } +}; diff --git a/src/plugins/StreamBitrate.js b/src/plugins/StreamBitrate.js new file mode 100644 index 0000000..2cb7085 --- /dev/null +++ b/src/plugins/StreamBitrate.js @@ -0,0 +1,59 @@ +'use strict'; + +/** + * Stream bitrate plugin. + * Provides video stream quality (audio and video bitrates) control. + */ +module.exports = class StreamBitrate { + /** + * Plugin initialization. + * + * @param {Object} instance Associated instance. + * @param {Object} i18n Translations keys for the UI. + */ + constructor(instance, i18n) { + // Reference instance + this.instance = instance; + + // Register plugin + this.instance.StreamBitrate = this; + this.i18n = i18n || {}; + + this.highQuality = false; + + // Display widget + this.renderToolbarButton(); + } + + /** + * Add the button to the player toolbar. + */ + renderToolbarButton() { + const toolbars = this.instance.getChildByClass(this.instance.root, 'gm-toolbar'); + if (!toolbars) { + return; // if we don't have toolbar, we can't spawn the widget + } + + const toolbar = toolbars.children[0]; + const button = document.createElement('li'); + this.chooser = document.createElement('div'); + this.chooser.className = '.gm-streamrate-chooser gm-icon-button gm-streamrate-button'; + this.chooser.title = this.i18n.STREAMRATE_TITLE || 'High quality'; + button.appendChild(this.chooser); + toolbar.appendChild(button); + this.chooser.onclick = () => { + this.highQuality = !this.highQuality; + this.chooser.classList.toggle('gm-active'); + if (this.highQuality) { + const json = {type: 'BITRATE', videoBitrate: 5000, audioBitrate: 192000}; + this.instance.sendEvent(json); + this.instance.renegotiateWebRTCConnection(); + } else { + // if we pass 0 here, we just use WebRTC default value + const json = {type: 'BITRATE', videoBitrate: 0, audioBitrate: 0}; + this.instance.sendEvent(json); + this.instance.renegotiateWebRTCConnection(); + } + }; + } +}; diff --git a/src/plugins/StreamResolution.js b/src/plugins/StreamResolution.js new file mode 100644 index 0000000..547467d --- /dev/null +++ b/src/plugins/StreamResolution.js @@ -0,0 +1,63 @@ +'use strict'; + +const RESOLUTIONS = [ + {text: '-', value: '0'}, + {text: '240p', value: '240'}, + {text: '360p', value: '360'}, + {text: '480p', value: '480'}, + {text: '720p', value: '720'}, + {text: '1080p', value: '1080'}, +]; + +/** + * Stream resolution plugin. + * Provides video stream resolution control. + */ +module.exports = class StreamResolution { + /** + * Plugin initialization. + * + * @param {Object} instance Associated instance. + * @param {Object} i18n Translations keys for the UI. + */ + constructor(instance, i18n) { + // Reference instance + this.instance = instance; + + // Register plugin + this.instance.StreamResolution = this; + this.i18n = i18n || {}; + + // Display widget + this.renderToolbarButton(); + } + + /** + * Add the button to the player toolbar. + */ + renderToolbarButton() { + const toolbars = this.instance.getChildByClass(this.instance.root, 'gm-toolbar'); + if (!toolbars) { + return; // if we don't have toolbar, we can't spawn the widget + } + + const toolbar = toolbars.children[0]; + this.select = document.createElement('select'); + this.select.className = 'gm-icon-button gm-streamres-button'; + this.select.title = this.i18n.STREAMRES_TITLE || 'Quality'; + RESOLUTIONS.forEach((resolution) => { + this.select.add(new Option(resolution.text, resolution.value)); + }); + this.select.onchange = this.onStreamResolutionChange.bind(this); + toolbar.appendChild(this.select); + } + + /** + * Apply the selected stream resolution. + */ + onStreamResolutionChange() { + const json = {type: 'SIZE', width: Number(this.select.value)}; + this.instance.sendEvent(json); + this.select.blur(); + } +}; diff --git a/src/plugins/util/OverlayPlugin.js b/src/plugins/util/OverlayPlugin.js new file mode 100644 index 0000000..925f974 --- /dev/null +++ b/src/plugins/util/OverlayPlugin.js @@ -0,0 +1,94 @@ +'use strict'; + +/** + * OverlayPlugin + * Extendable utility to auto-bind and handle genymotion 'closeOverlays' event. + * Expects implementer to provide list of overlays + */ +module.exports = class OverlayPlugin { + /** + * Plugin initialization + * @param {Object} instance Genymotion player instance + */ + constructor(instance) { + this.overlays = []; + this.savedState = null; + this.toolbarBtnImage = null; + this.instance = instance; + + // Listen for close trigger + this.instance.registerEventCallback('close-overlays', this.closeOverlays.bind(this)); + } + + /** + * Closes all active overlays and updates toolbar button state + */ + closeOverlays() { + this.overlays.forEach((overlay) => { + if (overlay && !overlay.classList.contains('gm-hidden')) { + overlay.classList.add('gm-hidden'); + if (overlay.onclose) { + overlay.onclose(); + } + } + }); + + this.instance.emit('keyboard-enable'); + + if (this.toolbarBtnImage) { + this.toolbarBtnImage.classList.remove('gm-active'); + } + } + + /** + * Save current button state (icon & click action) + */ + saveState() { + if (!this.savedState) { + this.savedState = { + toolbarBtn: { + className: this.toolbarBtn.className, + onclick: this.toolbarBtn.onclick, + }, + toolbarBtnImage: { + className: this.toolbarBtnImage.className, + }, + }; + } + } + + /** + * Re-apply the saved toolbar button state. + */ + restoreState() { + if (this.savedState) { + this.toolbarBtn.className = this.savedState.toolbarBtn.className; + this.toolbarBtnImage.className = this.savedState.toolbarBtnImage.className; + this.toolbarBtn.onclick = this.savedState.toolbarBtn.onclick; + + this.savedState = null; + } + } + + /** + * Disable associated toolbar icon. + */ + disable() { + if (this.toolbarBtn && this.toolbarBtnImage) { + this.saveState(); + + this.toolbarBtn.className += ' gm-disabled-widget-pop-up'; + this.toolbarBtnImage.className += ' gm-disabled-widget-icon'; + this.toolbarBtn.onclick = null; + } + } + + /** + * Enable associated toolbar icon. + */ + enable() { + if (this.toolbarBtn && this.toolbarBtnImage) { + this.restoreState(); + } + } +}; diff --git a/src/plugins/util/iothrottling-profiles.js b/src/plugins/util/iothrottling-profiles.js new file mode 100644 index 0000000..0186e8b --- /dev/null +++ b/src/plugins/util/iothrottling-profiles.js @@ -0,0 +1,27 @@ +'use strict'; + +/** + * List of available IO throttling profiles to send to VM + * + * readByteRate: The total rate in MegaBytes of read per second + * writeByteRate: The total rate in MegaBytes of write per second + * readIoRate: The number of read operation allowed per second + * writeIoRate: The number of write operation allowed per second + * + */ +module.exports = [{ + name: 'High-end device', + label: 'High-end device', + readByteRate: 200, +}, { + name: 'Mid-range device', + label: 'Mid-range device', + readByteRate: 100, +}, { + name: 'Low-end device', + label: 'Low-end device', + readByteRate: 50, +}, { + name: 'Custom', + label: 'Custom device', +}]; diff --git a/src/plugins/util/network-profiles.js b/src/plugins/util/network-profiles.js new file mode 100644 index 0000000..284a775 --- /dev/null +++ b/src/plugins/util/network-profiles.js @@ -0,0 +1,294 @@ +'use strict'; + +/** + * List of available network profiles to send to VM + */ +module.exports = [{ + id: 8, + name: 'wifi', + label: 'Wifi', + downSpeed: { + label: '40.0Mb/s', + value: 40000, + }, + downDelay: { + label: '0ms', + value: 0, + }, + downPacketLoss: { + label: '0%', + value: 0.0, + }, + upSpeed: { + label: '33.0Mb/s', + value: 33000, + }, + upDelay: { + label: '0ms', + value: 0, + }, + upPacketLoss: { + label: '0%', + value: 0.0, + }, + dnsDelay: { + label: '0ms', + value: 0, + }, +}, { + id: 7, + name: '4g_with_loss', + label: '4G (High packet losses)', + downSpeed: { + label: '17.9Mb/s', + value: 17900, + }, + downDelay: { + label: '50ms', + value: 50, + }, + downPacketLoss: { + label: '10%', + value: 10.0, + }, + upSpeed: { + label: '5.5Mb/s', + value: 5500, + }, + upDelay: { + label: '50ms', + value: 50, + }, + upPacketLoss: { + label: '10%', + value: 10.0, + }, + dnsDelay: { + label: '100ms', + value: 100, + }, +}, { + id: 6, + name: '4g_with_delay', + label: '4G (High DNS delay)', + downSpeed: { + label: '17.9Mb/s', + value: 17900, + }, + downDelay: { + label: '50ms', + value: 50, + }, + downPacketLoss: { + label: '0.01%', + value: 0.01, + }, + upSpeed: { + label: '5.5Mb/s', + value: 5500, + }, + upDelay: { + label: '50ms', + value: 50, + }, + upPacketLoss: { + label: '0.01%', + value: 0.01, + }, + dnsDelay: { + label: '3000ms', + value: 3000, + }, +}, { + id: 5, + name: '4g', + label: '4G', + downSpeed: { + label: '17.9Mb/s', + value: 17900, + }, + downDelay: { + label: '50ms', + value: 50, + }, + downPacketLoss: { + label: '0.01%', + value: 0.01, + }, + upSpeed: { + label: '5.5Mb/s', + value: 5500, + }, + upDelay: { + label: '50ms', + value: 50, + }, + upPacketLoss: { + label: '0.01%', + value: 0.01, + }, + dnsDelay: { + label: '100ms', + value: 100, + }, +}, { + id: 4, + name: '3g', + label: '3G', + downSpeed: { + label: '7.2Mb/s', + value: 7200, + }, + downDelay: { + label: '100ms', + value: 100, + }, + downPacketLoss: { + label: '0.01%', + value: 0.01, + }, + upSpeed: { + label: '1.5Mb/s', + value: 1500, + }, + upDelay: { + label: '100ms', + value: 100, + }, + upPacketLoss: { + label: '0.01%', + value: 0.01, + }, + dnsDelay: { + label: '200ms', + value: 200, + }, +}, { + id: 3, + name: 'edge', + label: 'EDGE', + downSpeed: { + label: '240Kb/s', + value: 240, + }, + downDelay: { + label: '400ms', + value: 400, + }, + downPacketLoss: { + label: '0.01%', + value: 0.01, + }, + upSpeed: { + label: '200Kb/s', + value: 200, + }, + upDelay: { + label: '400ms', + value: 400, + }, + upPacketLoss: { + label: '0.01%', + value: 0.01, + }, + dnsDelay: { + label: '800ms', + value: 800, + }, +}, { + id: 2, + name: 'gprs', + label: 'GPRS', + downSpeed: { + label: '40Kb/s', + value: 40, + }, + downDelay: { + label: '500ms', + value: 500, + }, + downPacketLoss: { + label: '0.01%', + value: 0.01, + }, + upSpeed: { + label: '40Kb/s', + value: 40, + }, + upDelay: { + label: '500ms', + value: 500, + }, + upPacketLoss: { + label: '0.01%', + value: 0.01, + }, + dnsDelay: { + label: '1000ms', + value: 1000, + }, +}, { + id: 1, + name: 'no_data', + label: 'No data', + downSpeed: { + label: '0Kb/s', + value: 0, + }, + downDelay: { + label: '0ms', + value: 0, + }, + downPacketLoss: { + label: '0%', + value: 0.0, + }, + upSpeed: { + label: '0Kb/s', + value: 0, + }, + upDelay: { + label: '0ms', + value: 0, + }, + upPacketLoss: { + label: '0%', + value: 0.0, + }, + dnsDelay: { + label: '0ms', + value: 0, + }, +}, { + id: 0, + name: 'native', + label: 'Native', + downSpeed: { + label: 'N/A', + value: Infinity, + }, + downDelay: { + label: 'N/A', + value: 0, + }, + downPacketLoss: { + label: 'N/A', + value: 0, + }, + upSpeed: { + label: 'N/A', + value: Infinity, + }, + upDelay: { + label: 'N/A', + value: 0, + }, + upPacketLoss: { + label: 'N/A', + value: 0, + }, + dnsDelay: { + label: 'N/A', + value: 0, + }, +}]; diff --git a/src/scss/base/_genymotion.scss b/src/scss/base/_genymotion.scss new file mode 100644 index 0000000..535ae5b --- /dev/null +++ b/src/scss/base/_genymotion.scss @@ -0,0 +1,119 @@ +/** + * Common player style + */ +.gm-player-instance { + text-align: center; + + *, *::after, *::before { + box-sizing: border-box; + } + + .invisible { + opacity: 0; + } + + .hidden { + display: none !important; + } + + &:focus { + outline: 0; + } + + ul { + list-style-type: none; + padding: 0; + margin: 0; + + li img { + width: 24px; + } + } + + .gm { + &-video { + margin: 0; + max-width: 100%; + } + + &-icon-button { + display: block; + width: 32px; + height: 26px; + margin: 16px auto 16px auto; + } + + &-video-overlay { + position: absolute; + z-index: 1; + cursor: pointer; + background-color: $black; + color: $white; + text-align: center; + display: block; + width: calc(100% - 55px); + height: 100%; + left: 0; + top: 0; + } + + &-click-to-display { + background: black url("../assets/images/ic_click_to_display_default.svg") no-repeat center; + background-size: calc(150px + 10%); + + &:hover { + background-image: url("../assets/images/ic_click_to_display_hover.svg"); + } + } + + &-click-to-unmute { + background-color: darken(#223140, 15%); + background: darken(#223140, 15%) url("../assets/images/ic_icon_mute.svg") no-repeat center; + background-position: 15px 20px; + background-size: 30px; + border-radius: 8px; + font-size: 15px; + text-align: left; + font-family: Roboto, sans-serif; + padding: 16px 20px 17px 60px; + position: absolute; + z-index: 1; + color: $white; + display: block; + width: 80%; + max-width: 380px; + min-height: 66px; + left: calc(10% - 30px); + top: calc(86% - 34px); + cursor: pointer; + @media screen and (min-width: 475px) { + left: calc(50% - 220px); + } + } + + &-overlay-cant-connect { + background: black url("../assets/images/ic_error_default.svg") no-repeat center 40%; + background-size: 200px; + font-size: 28px; + font-family: Roboto, sans-serif; + font-weight: 300; + padding-top: 10%; + + .gm-error-text { + position: absolute; + top: calc(40% + 140px); + width: 90%; + padding-left: 10%; + } + + p { + font-size: 50%; + font-weight: normal; + } + + a { + color: $btn-background-color; + } + } + } +} diff --git a/src/scss/base/_variables.scss b/src/scss/base/_variables.scss new file mode 100644 index 0000000..252a89d --- /dev/null +++ b/src/scss/base/_variables.scss @@ -0,0 +1,19 @@ +/** + * SASS variables + */ + +// General use +$white: #ffffff; +$black: #000000; +$accent-color-light: #e6195e; + +// Responsive breakpoint +$breakpoint-mobile: 650px; + +// Elements +$btn-background-color: #e6195e; +$btn-background-color-hover: #c62c53; +$btn-disabled-background: rgba(179, 179, 179, 0.24); +$btn-disabled-color: #c4c4c4; +$btn-disabled-background-hover: #828282; +$modal-background-color: #303339; diff --git a/src/scss/components/_battery.scss b/src/scss/components/_battery.scss new file mode 100644 index 0000000..7be926f --- /dev/null +++ b/src/scss/components/_battery.scss @@ -0,0 +1,79 @@ +/** + * Battery plugin styles + */ +.gm-player-instance .gm-battery-plugin { + .gm { + &-charging-group { + margin-top: 15px; + + .gm-charging-checkbox { + width: 15px; + float: left; + margin: 0; + } + + .gm-charging-status { + height: 32px; + line-height: 32px; + font-weight: bold; + margin-left: 20px; + + &.charging { + color: $accent-color-light; + } + } + } + + &-charge-level-group { + height: 75px; + display: flex; + justify-content: space-around; + align-items: center; + + * { + width: 33%; + text-align: center; + } + + .gm-charge-image { + position: relative; + width: 35px; + height: 60px; + background: url("../assets/images/ic-battery_empty.svg") no-repeat center; + background-size: 32px; + margin: 0 auto; + + .gm-charge-image-overlay { + position: absolute; + left: 10%; + bottom: 3px; + width: 80%; + height: 0; + background-color: $white; + } + + .gm-full-charge-image-overlay { + position: absolute; + left: 37%; + bottom: 10px; + width: 27%; + height: 0; + background-color: $white; + } + } + + .gm-charge-input { + width: 80px; + margin: 0 4px 0 0; + } + + .gm-charge-slider { + margin: 0; + width: 65px; + height: 31px; + transform: rotate(270deg); + padding: 0 3px; + } + } + } +} diff --git a/src/scss/components/_clipboard.scss b/src/scss/components/_clipboard.scss new file mode 100644 index 0000000..f1d3c14 --- /dev/null +++ b/src/scss/components/_clipboard.scss @@ -0,0 +1,19 @@ +/** + * Clipboard plugin styles + */ +.gm-player-instance .gm-clipboard-plugin { + .gm { + &-clipboard-input { + min-height: 300px; + resize: none; + color: $black !important; + background-color: $white !important; + } + + &-text-copied { + padding: 15px 0 0 30px; + transition: opacity 0.5s ease-in-out; + background: url("../assets/images/ic_clipboard_inactive.svg") no-repeat left 10px !important; + } + } +} diff --git a/src/scss/components/_fullscreen.scss b/src/scss/components/_fullscreen.scss new file mode 100644 index 0000000..97e7d40 --- /dev/null +++ b/src/scss/components/_fullscreen.scss @@ -0,0 +1,36 @@ +/** + * Fullscreen plugin styles + */ +.gm-player-instance .gm-fullscreen { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + padding: 0; + + .gm { + &-player { + background: $black !important; + height: 100%; + max-height: 100% !important; + } + + &-video { + position: absolute; + top: 0; + left: 0; + width: calc(100% - 60px); + height: 100%; + padding: 0; + } + + &-toolbars { + position: absolute; + top:0; + right: 0; + width: 48px; + height: 100%; + } + } +} diff --git a/src/scss/components/_gps.scss b/src/scss/components/_gps.scss new file mode 100644 index 0000000..8aa2f54 --- /dev/null +++ b/src/scss/components/_gps.scss @@ -0,0 +1,50 @@ +/** + * GPS plugin styles + */ +.gm-player-instance .gm-gps { + &-controls { + label { + margin-top: 10px; + } + + input { + &.gm-error { + border-bottom: 1px solid $btn-background-color; + } + } + } + + &-submit { + margin-top: 10px; + } + + &-geoloc { + margin-top: 10px; + } + + &-mapview { + height: 460px; + + .gm-mapview { + position: absolute; + bottom: 76px; + left: 26px; + right: 26px; + top: 26px; + background-color: $white; + } + + .gm-gps-mapview-capture { + position: absolute; + bottom: 20px; + left: calc(50% + 80px); + } + + .gm-gps-mapview-cancel { + position: absolute; + bottom: 20px; + right: calc(50% + 80px); + } + } + +} diff --git a/src/scss/components/_imei.scss b/src/scss/components/_imei.scss new file mode 100644 index 0000000..2879a36 --- /dev/null +++ b/src/scss/components/_imei.scss @@ -0,0 +1,30 @@ +/** + * Identifiers (IMEI) plugin styles + */ +.gm-player-instance .gm-identifiers-plugin { + .gm-identifier-device, .gm-identifier-android { + .gm-description { + font-size: 90%; + padding-left: 10px; + } + + margin-bottom: 16px; + + .gm-input-group { + display: flex; + + button { + margin-top: -5px; + } + } + } + + input { + margin-right: 6px; + flex: 1; + + &.gm-error { + border-bottom: 1px solid $btn-background-color; + } + } +} diff --git a/src/scss/components/_iothrottling.scss b/src/scss/components/_iothrottling.scss new file mode 100644 index 0000000..a53c6da --- /dev/null +++ b/src/scss/components/_iothrottling.scss @@ -0,0 +1,57 @@ +/** + * IO Throttling plugin styles + */ +.gm-player-instance .gm-iothrottling-plugin { + .gm-inputs { + margin-bottom: 15px; + + select { + font-size: medium; + width: 100%; + margin-top:10px; + padding: 2px; + } + } + + label { + margin-top: 20px; + display: block; + float: left; + } + + .gm-fields { + display: block; + margin: 0; + padding: 0; + width: 100%; + height: 50px; + } + + .gm-units { + text-align: right; + float: right; + width: 160px; + } + + input { + font-size: medium; + font-family: Helvetica,sans-serif; + margin-top: 10px; + width: 30%; + text-align: right; + float: right; + + &:read-only { + border-bottom: 1px solid transparent; + background: $btn-disabled-background; + } + + &:required:invalid, &:focus:invalid { + border-bottom: 1px solid $btn-background-color; + } + } + + button { + margin-top: 20px; + } +} diff --git a/src/scss/components/_network.scss b/src/scss/components/_network.scss new file mode 100644 index 0000000..c1ad606 --- /dev/null +++ b/src/scss/components/_network.scss @@ -0,0 +1,60 @@ +/** + * Network plugin styles + */ +.gm-player-instance .gm-network-plugin { + .gm { + &-inputs { + margin-bottom: 15px; + + select { + width: 100%; + margin-top: 10px; + padding: 2px; + } + } + + &-profile-details { + margin: 12px 0; + } + + &-section { + display: block; + margin: 20px 0 10px 0; + padding: 0; + width: 100%; + height: 50px; + font-weight: bold; + border-bottom: 1px solid $white; + } + + &-fields { + display: block; + padding: 0; + width: 100%; + height: 50px; + } + } + + label { + margin-top: 20px; + display: block; + float: left; + } + + input { + margin-top: 10px; + width: 60%; + float: right; + text-align: right; + font-size: medium; + font-family: Helvetica, sans-serif; + + &:invalid, &:focus:invalid { + border-bottom: 1px solid $btn-background-color; + } + } + + button { + margin-top: 20px; + } +} diff --git a/src/scss/components/_phone.scss b/src/scss/components/_phone.scss new file mode 100644 index 0000000..c49b492 --- /dev/null +++ b/src/scss/components/_phone.scss @@ -0,0 +1,19 @@ +/** + * Phone plugin styles + */ +.gm-player-instance .gm-phone-plugin { + .gm-phone-group { + &:first-child { + margin-bottom: 12px; + } + } + + input, textarea { + margin-bottom: 4px; + } + + textarea { + resize: none; + width: 100%; + } +} diff --git a/src/scss/components/_screencast.scss b/src/scss/components/_screencast.scss new file mode 100644 index 0000000..5584a81 --- /dev/null +++ b/src/scss/components/_screencast.scss @@ -0,0 +1,90 @@ +/** + * Screencast plugin styles + */ +.gm-player-instance { + .gm-screencast-plugin { + width: 400px; + left: calc(50% - 200px); + + /* Extra Small Devices, Tablet or Phones */ + @media only screen and (max-width : $breakpoint-mobile) { + max-width: 400px; + } + + label { + height: 32px; + line-height: 35px; + margin-bottom: 0; + margin-left: 20px; + cursor: pointer; + } + + .disabled { + opacity: 0.4; + pointer-events: none; + } + + .gm-screenshot, .gm-screencast { + display: inline-block; + width: auto; + margin-right: 50px; + + .gm-action { + width: 32px; + min-height: 32px; + cursor: pointer; + display: block; + float: left; + background-size: 26px; + background-repeat: no-repeat; + background-position: center; + } + } + + .gm-screenshot .gm-action { + background-image: url("../assets/images/ic-screenshot_default.svg"); + + } + + .gm-screencast .gm-action { + background-image: url("../assets/images/ic-screencast_default.svg"); + + .disabled { + background-image: url("../assets/images/ic-screencast_disabled.svg"); + color: $btn-disabled-background; + } + + } + } + + .gm-screencast-timer { + position: relative; + top: -10px; + left: -90px; + color: #c6225a; + font-size: 20px; + font-family: Helvetica, sans-serif; + pointer-events: none; + z-index: 5; + padding: 11px 8px 8px 8px; + border-radius: 6px; + width: 80px; + background-color: $modal-background-color; + vertical-align: middle; + + &::after { + content: " "; + position: absolute; + top: 50%; + left: 100%; /* To the right of the tooltip */ + margin-top: -5px; + border-width: 5px; + border-style: solid; + border-color: transparent transparent transparent $modal-background-color; + } + } + + .gm-timer-hidden { + display: none; + } +} \ No newline at end of file diff --git a/src/scss/components/_toolbar.scss b/src/scss/components/_toolbar.scss new file mode 100644 index 0000000..8e146d7 --- /dev/null +++ b/src/scss/components/_toolbar.scss @@ -0,0 +1,186 @@ +/** + * Player toolbar styles + */ +.gm-player-instance { + .gm-toolbar img:hover, + .gm-streamrate-chooser img:hover { + cursor: pointer; + } + + .gm { + &-icon-button { + background-size: contain; + background-repeat: no-repeat; + background-position: center; + &:hover { + cursor: pointer; + } + } + + &-rotation { + background-image: url("../assets/images/ic_rotation_inactive.svg"); + &:hover { + background-image: url("../assets/images/ic_rotation_active.svg"); + } + } + + &-sound-up { + background-image: url("../assets/images/ic_sound_up_inactive.svg"); + &:hover { + background-image: url("../assets/images/ic_sound_up_active.svg"); + } + } + + &-sound-down { + background-image: url("../assets/images/ic_sound_down_inactive.svg"); + &:hover { + background-image: url("../assets/images/ic_sound_down_active.svg"); + } + } + + &-recent { + background-image: url("../assets/images/ic-nav_android_multiapp_inactive.svg"); + &:hover { + background-image: url("../assets/images/ic-nav_android_multiapp_active.svg"); + } + } + + &-home { + background-image: url("../assets/images/ic-nav_android_home_inactive.svg"); + &:hover { + background-image: url("../assets/images/ic-nav_android_home_active.svg"); + } + } + + &-back { + background-image: url("../assets/images/ic-nav_android_back_inactive.svg"); + &:hover { + background-image: url("../assets/images/ic-nav_android_back_active.svg"); + } + } + + &-battery-button { + background-image: url("../assets/images/ic-battery_inactive.svg"); + &:hover, &.gm-active { + background-image: url("../assets/images/ic-battery_active.svg"); + } + } + + &-power { + background-image: url("../assets/images/ic_icon_power_inactive.svg"); + &:hover { + background-image: url("../assets/images/ic_icon_power_active.svg"); + } + } + + &-camera-button { + background-image: url("../assets/images/ic_camera_inactive.svg"); + &:hover { + background-image: url("../assets/images/ic_camera_active.svg"); + } + } + + &-streamres-button { + background-image: url("../assets/images/ic-resolution_inactive.svg"); + background-color: transparent; + outline: none; + border: none; + color :transparent; + -webkit-appearance: none; + -moz-appearance: none; + + &:focus { + outline-style: none; + box-shadow: none; + border-color: transparent; + color: $white; + background: $black !important; + } + + &:hover { + background-image: url("../assets/images/ic-resolution_active.svg"); + } + } + + &-gps-button, &-gps-button.gm-active { + background-image: url("../assets/images/ic_location_inactive.svg"); + &:hover { + background-image: url("../assets/images/ic_location_active.svg"); + } + } + + &-fullscreen-button { + background-image: url("../assets/images/ic_fullscreen_inactive.svg"); + &:hover { + background-image: url("../assets/images/ic_fullscreen_active.svg"); + } + &.gm-active, &.gm-active:hover { + background-image: url("../assets/images/ic_fullscreen_exit_active.svg"); + } + } + + &-screencast-button { + background-image: url("../assets/images/ic-screenshot_inactive.svg"); + &:hover, &.gm-active, &.gm-active:hover { + background-image: url("../assets/images/ic-screenshot_active.svg"); + } + } + + &-screencast-button-recording { + background-image: url("../assets/images/ic-screenshot_active.svg"); + } + + &-identifiers-button { + background-image: url("../assets/images/ic_id_inactive.svg"); + &:hover, &.gm-active, &.gm-active:hover { + background-image: url("../assets/images/ic_id_active.svg"); + } + } + + &-network-button { + background-image: url("../assets/images/ic_network_inactive.svg"); + &:hover, &.gm-active, &.gm-active:hover { + background-image: url("../assets/images/ic_network_active.svg"); + } + } + + &-iothrottling-button { + background-image: url("../assets/images/ic_diskIO_inactive.svg"); + &:hover, &.gm-active, &.gm-active:hover { + background-image: url("../assets/images/ic_diskIO_active.svg"); + } + } + + &-phone-button { + background-image: url("../assets/images/ic_textandcall_inactive.svg"); + &:hover, &.gm-active { + background-image: url("../assets/images/ic_textandcall_active.svg"); + } + } + + &-uploader-button { + background-image: url("../assets/images/ic_installation_inactive.svg"); + &:hover, &.gm-active { + background-image: url("../assets/images/ic_installation_active.svg"); + } + } + + &-streambitrate-button { + background-image: url("../assets/images/hq.png"); + &:hover, &.gm-active { + background-image: url("../assets/images/hq-over.png"); + } + } + + &-clipboard-button { + background-image: url("../assets/images/ic_clipboard_inactive.svg"); + &:hover, &.gm-active { + background-image: url("../assets/images/ic_clipboard_active.svg"); + } + } + + &-default-turn-button { + background-image: url("../assets/images/ic_warning.svg"); + } + } +} diff --git a/src/scss/components/_turn.scss b/src/scss/components/_turn.scss new file mode 100644 index 0000000..83d22d9 --- /dev/null +++ b/src/scss/components/_turn.scss @@ -0,0 +1,49 @@ +/** + * Turn server plugin styles + */ + +.gm-player-instance .gm-default-turn-button { + text-decoration: none; + + .gm-default-turn-used { + position: relative; + top: -48px; + left: -305px; + color: $white; + font-size: 1em; + font-family: Helvetica, sans-serif; + pointer-events: none; + z-index: 5; + border-radius: 6px; + width: 290px; + background-color: $modal-background-color; + vertical-align: middle; + padding: 11px 8px 20px; + + &::after { + content: " "; + position: absolute; + top: 50%; + left: 100%; /* To the right of the tooltip */ + margin-top: -10px; + border-width: 10px; + border-style: solid; + border-color: transparent transparent transparent $modal-background-color; + } + + h1 { + font-size: 1.1em; + color: $accent-color-light; + padding-bottom: 5px; + + span { + font-weight: bolder; + font-size: 1.2em; + } + } + } + + .gm-hidden { + display: none; + } +} diff --git a/src/scss/components/_upload.scss b/src/scss/components/_upload.scss new file mode 100644 index 0000000..deb694f --- /dev/null +++ b/src/scss/components/_upload.scss @@ -0,0 +1,209 @@ +/** + * Upload plugin styles + */ +.gm-player-instance { + .gm { + &-wrapper { + display: inline-block; + border: 10px solid transparent; + } + + &-dragover { + border: 10px solid $accent-color-light; + } + + &-upload-progress { + display: block; + position: absolute; + left: 5%; + top: 5%; + z-index: 1; + } + + &-custom-file-upload { + display: inline; + } + + &-upload-main { + text-align: center; + + &-img { + width: 58px; + margin-top: 30px; + } + + &-txt { + margin-top: 15px; + font-size: 16px; + } + } + + &-upload-disclaimer { + &-txt { + height: 336px; + overflow: auto; + margin-top: 30px; + } + + &-txt::-webkit-scrollbar { + width: 20px; + } + + &-txt::-webkit-scrollbar-track { + background: #45474D; + border-left: 9px solid $modal-background-color; + border-right: 9px solid $modal-background-color; + } + + &-txt::-webkit-scrollbar-thumb { + background: white; + border-left: 8px solid $modal-background-color; + border-right: 8px solid $modal-background-color; + border-radius: 9px; + } + } + + &-upload-in-progress { + margin-top: 30px; + padding-right: 30px; + padding-left: 30px; + + &-txt-progress { + display: inline-block; + } + + &-txt-percent { + display: block; + float: right; + } + + &-bg-percent { + height: 3px; + background-color: #D8D8D8; + margin-top: 5px; + } + + &-percent { + height: 3px; + background-color: $btn-background-color; + } + } + + &-upload-error { + text-align: center; + margin-top: 30px; + + &-img { + width: 58px; + } + + &-caption { + font-size: 16px; + margin-top: 15px; + margin-bottom: 30px; + } + + &-button { + margin-top: 26px; + display: inline-block; + padding: 10px; + text-transform: uppercase; + font-weight: bold; + font-size: 14px; + cursor: pointer; + color: $white; + background-color: $btn-background-color; + border-radius: 2px; + margin-bottom: 10px; + + &:hover { + background-color: $btn-background-color-hover; + color: $white; + } + } + } + + &-upload-success { + text-align: center; + margin-top: 30px; + + &-img { + width: 58px; + } + + &-txt { + font-size: 16px; + } + + &-caption { + font-size: 16px; + margin-top: 15px; + margin-bottom: 30px; + } + + &-button { + margin-top: 26px; + display: inline-block; + padding: 10px; + text-transform: uppercase; + font-weight: bold; + font-size: 14px; + cursor: pointer; + color: $white; + background-color: $btn-background-color; + border-radius: 2px; + margin-bottom: 10px; + + &:hover { + background-color: $btn-background-color-hover; + color: $white; + } + } + } + + &-upload-main-bottom-buttons { + float: right; + margin-top: 30px; + + &-left, &-right { + display: inline-block; + padding: 10px; + text-transform: uppercase; + font-weight: bold; + font-size: 14px; + cursor: pointer; + color: $white; + background-color: $btn-background-color; + border-radius: 2px; + &:hover { + background-color: $btn-background-color-hover; + color: $white; + } + } + + &-left { + margin-right: 15px; + } + } + + &-upload-main-bottom-buttons-disabled, &-upload-main-bottom-buttons-disabled:hover { + cursor: default; + color: $btn-disabled-color; + background-color: $btn-disabled-background; + } + + &-upload-title { + font-weight: bold; + font-size: 20px; + } + + &-uploader-plugin { + min-height: unset; + width: 640px; + } + } + + input[type="file"] { + display: none; + } +} diff --git a/src/scss/components/_uploader.scss b/src/scss/components/_uploader.scss new file mode 100644 index 0000000..82639f1 --- /dev/null +++ b/src/scss/components/_uploader.scss @@ -0,0 +1,26 @@ +/** + * File upload plugin styles + */ +.gm-player-instance .gm-uploader-content { + .gm { + &-upload-icon { + display: inline-block; + height: 39px; + width: 58px; + background-repeat: no-repeat; + background-position: center center; + } + + &-upload-main-img { + background-image: url("../assets/images/ic_cloud_upload.svg"); + } + + &-upload-success-img { + background-image: url("../assets/images/ic_cloud_upload_congralutation.svg"); + } + + &-upload-error-img { + background-image: url("../assets/images/ic_cloud_upload_failed.svg"); + } + } +} diff --git a/src/scss/components/_widgetwindow.scss b/src/scss/components/_widgetwindow.scss new file mode 100644 index 0000000..01e5fe3 --- /dev/null +++ b/src/scss/components/_widgetwindow.scss @@ -0,0 +1,167 @@ +/** + * Widget window styles + */ +.gm-overlay { + font-family: Helvetica, sans-serif; + text-align: left; + position: absolute; + padding: 25px; + width: 500px; + left: calc(50% - 250px); + min-height: 400px; + top: 50px; + background-color: $modal-background-color; + color: $white; + border: none; + border-radius: 2px; + + @media only screen and (max-width : $breakpoint-mobile) { + max-width: 500px; + width: calc(80% - 40px) !important; + left: 10% !important; + } + + transition: top .4s; + -webkit-transition: top .25s ease-out; + + &.gm-hidden { + top: -1000px; + } + + .gm-wrap:after, .gm-horizontal:after { + display: table; + content: " "; + clear: both; + } + + .gm-col { + width: 50%; + float: left; + padding: 0 5px; + } + + .gm-title { + text-align: center; + margin-bottom: 30px; + } + + .gm-horizontal { + margin: 15px 0; + + label, input, button { + display: inline-block; + } + + label { + width: 50%; + } + } + + button { + color: $white; + background-color: $btn-background-color; + padding: 11px 25px; + + border-radius: 2px; + border: none; + transition: all 0.3s ease; + text-transform: uppercase; + outline: none; + outline-style: none; + + &:hover, &:focus { + cursor: pointer; + background-color: $btn-background-color-hover; + } + + &:disabled { + pointer-events: none; + transition: all 0.3s ease; + background: $btn-disabled-background; + color: $btn-disabled-color; + + &:hover{ + color: $btn-disabled-background-hover; + } + } + } + + label { + display: block; + margin-bottom: 3px; + } + + input, textarea { + // background-color: #444; + background: transparent; + color: $white; + + // border: 1px solid black; + border: none; + border-bottom: 1px solid $white; + + padding: 0 8px; + width: 100%; + outline: none; + + &:focus { + outline: none; + } + } + + select { + color: initial; + } + + input { + height: 32px; + } + + textarea { + padding: 8px; + } + + .gm-close-btn { + position: absolute; + top: 10px; + right: 10px; + width: 30px; + height: 30px; + background: url("../assets/images/ic-close-popup-default.svg") no-repeat top center; + + &:hover { + cursor: pointer; + background: url("../assets/images/ic-close-popup-hover.svg") no-repeat top center; + } + } +} + +.gm-disabled-widget-pop-up { + &::before { + position: relative; + float: left; + left: -220px; + top: -7px; + color: $white; + font-size: 15px; + font-family: Roboto, sans-serif; + pointer-events: none; + z-index: 5; + padding: 12px 8px 10px 8px; + width: 210px; + background-color: $modal-background-color; + vertical-align: middle; + content: "Not\00a0 currently\00a0supported"; + display: none; + } + + :hover::before { + display: block; + } +} + + +.gm-disabled-widget-icon { + opacity: 0.3; + pointer-events: none; +} diff --git a/src/scss/main.scss b/src/scss/main.scss new file mode 100644 index 0000000..3c9b422 --- /dev/null +++ b/src/scss/main.scss @@ -0,0 +1,22 @@ +/** + * Main stylesheet. + * Only imports other styles. + */ + +@import "base/_variables"; +@import "base/_genymotion"; + +@import "components/_widgetwindow"; +@import "components/_fullscreen"; +@import "components/_toolbar"; +@import "components/_upload"; +@import "components/_battery"; +@import "components/_gps"; +@import "components/_screencast"; +@import "components/_imei"; +@import "components/_network"; +@import "components/_iothrottling"; +@import "components/_phone"; +@import "components/_uploader"; +@import "components/_clipboard"; +@import "components/_turn"; diff --git a/src/templates/bootstrap/dom.html b/src/templates/bootstrap/dom.html new file mode 100644 index 0000000..a934507 --- /dev/null +++ b/src/templates/bootstrap/dom.html @@ -0,0 +1,14 @@ +
+
+ +
+ +
+
+
    +
+
+
+
diff --git a/src/templates/bootstrap/script.js b/src/templates/bootstrap/script.js new file mode 100644 index 0000000..e69de29 diff --git a/src/templates/bootstrap/style.css b/src/templates/bootstrap/style.css new file mode 100644 index 0000000..d71116a --- /dev/null +++ b/src/templates/bootstrap/style.css @@ -0,0 +1,36 @@ +.gm_bootstrap .gm-video { + background: transparent; + background-size: contain; + background-position: center; + width: 99% +} + +.gm_bootstrap { + background-color: black; +} + +.gm_bootstrap .gm-toolbars { + position: absolute; + width: 47px; + height: 100%; + top: 0; + right: 0; + margin: 0; +} + +.gm_bootstrap .gm-toolbar { + position: absolute; + top: 5%; + right: 0; + margin: 0; +} + +.gm_bootstrap li img { + margin: auto +} + +@media (min-width: 1200px) { + .gm_bootstrap li img { + width: 85%; + } +} diff --git a/src/templates/fullscreen/dom.html b/src/templates/fullscreen/dom.html new file mode 100644 index 0000000..a3a973e --- /dev/null +++ b/src/templates/fullscreen/dom.html @@ -0,0 +1,18 @@ + + + +
+
+ +
+
+
+
    +
+
+
+
+ + diff --git a/src/templates/fullscreen/script.js b/src/templates/fullscreen/script.js new file mode 100644 index 0000000..e69de29 diff --git a/src/templates/fullscreen/style.css b/src/templates/fullscreen/style.css new file mode 100644 index 0000000..483334d --- /dev/null +++ b/src/templates/fullscreen/style.css @@ -0,0 +1,41 @@ +.gm-fullscreen { + position: absolute; + top: 0; + left: 0; + margin: 0; + padding: 0; + display: block; + width: 100%; + height: 97%; + background-color: black; +} + +.gm-fullscreen .gm-fullscreen-message { + display: block; + padding: 0; + margin: 0; + height: 100%; + width: 100%; + background: white; + background-size: cover; +} + +.gm-video .hide { + display: none; +} + +.gm-fullscreen .gm-video { + background: transparent; + position: absolute; + top: 0; + left: 0; + width: 95%; + height: 100%; + padding: 0; +} + +.gm-toolbars { + position: absolute; + top: 0; + right: 0; +} diff --git a/src/templates/fullwindow/dom.html b/src/templates/fullwindow/dom.html new file mode 100644 index 0000000..97e0656 --- /dev/null +++ b/src/templates/fullwindow/dom.html @@ -0,0 +1,12 @@ +
+
+ +
+
+
    +
+
+
+ diff --git a/src/templates/fullwindow/script.js b/src/templates/fullwindow/script.js new file mode 100644 index 0000000..e69de29 diff --git a/src/templates/fullwindow/style.css b/src/templates/fullwindow/style.css new file mode 100644 index 0000000..73715a8 --- /dev/null +++ b/src/templates/fullwindow/style.css @@ -0,0 +1,31 @@ +.gm_fullwindow { + position: absolute; + top: 0; + left: 0; + margin: 0; + padding: 0; + display: block; + width: 100%; + height: 97%; + min-height: 560px; + background-color: black; +} + +.gm_fullwindow .gm-video { + background: transparent; + position: absolute; + top: 0; + left: 0; + width: calc(95% - 50px); + height: 100%; + padding: 0; +} + +.gm_fullwindow .toolbar { + position: absolute; + top: 10px; + right: 0; + padding-right: 10px; + margin: 0; + width: 50px; +} diff --git a/src/templates/player/dom.html b/src/templates/player/dom.html new file mode 100644 index 0000000..55c0922 --- /dev/null +++ b/src/templates/player/dom.html @@ -0,0 +1,15 @@ +
+
+
+ +
+
+
+
    +
+
+
+
+
diff --git a/src/templates/player/script.js b/src/templates/player/script.js new file mode 100644 index 0000000..e69de29 diff --git a/src/templates/player/style.css b/src/templates/player/style.css new file mode 100644 index 0000000..cb4ab00 --- /dev/null +++ b/src/templates/player/style.css @@ -0,0 +1,23 @@ +.gm-template-player .gm-player { + position: relative; + border-collapse: separate; + border-radius: 3px; + padding: 40px 10px 40px 10px; + margin-left: auto; + margin-right: auto; + background-color: black; +} + +.gm-template-player .gm-video { + background: transparent url("../../assets/images/spinner-material.svg") no-repeat center; + width: 1024px; + height: 600px; + margin-right: 60px; +} + +.gm-template-player .gm-toolbars { + position: absolute; + top: 0; + right: 0; + width: 60px; +} diff --git a/src/templates/player_minimal/dom.html b/src/templates/player_minimal/dom.html new file mode 100644 index 0000000..ab2de35 --- /dev/null +++ b/src/templates/player_minimal/dom.html @@ -0,0 +1,12 @@ +
+
+ +
+
+
    +
+
+ +
diff --git a/src/templates/player_minimal/script.js b/src/templates/player_minimal/script.js new file mode 100644 index 0000000..e69de29 diff --git a/src/templates/player_minimal/style.css b/src/templates/player_minimal/style.css new file mode 100644 index 0000000..572c0fa --- /dev/null +++ b/src/templates/player_minimal/style.css @@ -0,0 +1,41 @@ +.gm-template-player_minimal { + position: absolute; + top: 0; + left: 0; + margin: 0; + padding: 0; + display: block; + width: 100%; + height: 100%; + min-height: 560px; + background-color: black; +} + +.gm-template-player_minimal .gm-video { + position: fixed; + top: 0; + left: 0; + width: calc(100vw - 57px); + height: 100vh; + padding: 0; + margin: 0; + background: transparent url("../../assets/images/loader.svg") center no-repeat; + background-size: 40%; +} + +.gm-template-player_minimal .gm-toolbar { + position: absolute; + top: 10px; + right: 0; + padding-right: 5px; + margin: 0; + width: 50px; +} + +.gm-template-player_minimal .gm-version-number { + position: fixed; + right: 5px; + bottom: 5px; + z-index: 2; + color: white; +} diff --git a/src/templates/player_no_toolbar/dom.html b/src/templates/player_no_toolbar/dom.html new file mode 100644 index 0000000..a1935a5 --- /dev/null +++ b/src/templates/player_no_toolbar/dom.html @@ -0,0 +1,7 @@ +
+
+ +
+
\ No newline at end of file diff --git a/src/templates/player_no_toolbar/script.js b/src/templates/player_no_toolbar/script.js new file mode 100644 index 0000000..e69de29 diff --git a/src/templates/player_no_toolbar/style.css b/src/templates/player_no_toolbar/style.css new file mode 100644 index 0000000..8e01842 --- /dev/null +++ b/src/templates/player_no_toolbar/style.css @@ -0,0 +1,23 @@ +.gm-template-player_no_toolbar { + position: absolute; + top: 0; + left: 0; + margin: 0; + padding: 0; + display: block; + width: 100%; + height: 100%; + min-height: 560px; + background-color: black; +} + +.gm-template-player_no_toolbar .gm-video { + position: fixed; + top: 0; + left: 0; + width: calc(95% - 50px); + height: 100%; + padding: 0; + background: transparent url("../../assets/images/loader.svg") center no-repeat; + background-size: 40%; +} diff --git a/src/templates/player_partial/dom.html b/src/templates/player_partial/dom.html new file mode 100644 index 0000000..ab2de35 --- /dev/null +++ b/src/templates/player_partial/dom.html @@ -0,0 +1,12 @@ +
+
+ +
+
+
    +
+
+ +
diff --git a/src/templates/player_partial/script.js b/src/templates/player_partial/script.js new file mode 100644 index 0000000..e69de29 diff --git a/src/templates/player_partial/style.css b/src/templates/player_partial/style.css new file mode 100644 index 0000000..c7df440 --- /dev/null +++ b/src/templates/player_partial/style.css @@ -0,0 +1,74 @@ +.gm-template-player_partial { + top: 0; + left: 0; + margin: 0; + padding: 0; + display: block; + min-height: 800px; + height: 100%; + background-color: black; +} + +.gm-template-player_partial .gm-wrapper { + top: 0; + left: 0; + margin: 0; + padding: 0; + display: block; + width: 100%; + height: 100%; +} + +.gm-template-player_partial .gm-video-wrapper { + position: relative; + top: 0; + left: 0; + margin: 0; + padding: 0; + display: block; + width: 100%; + height: 100%; +} + +.gm-template-player_partial .gm-video { + position: relative; + top: 0; + left: 0; + width: calc(95% - 50px); + height: 100%; + padding: 0; + background: transparent url("../../assets/images/loader.svg") center no-repeat; + background-size: 40%; +} + +.gm-template-player_partial .gm-toolbar { + position: absolute; + top: 10px; + right: 0; + padding-right: 5px; + margin: 0; + width: 50px; +} + +.gm-template-player_partial .gm-version-number { + position: fixed; + right: 5px; + bottom: 5px; + z-index: 2; + color: white; +} + +@media only screen and (max-width: 650px) { + .gm-overlay { + left: auto; + width: calc(100vw - 100px); + right: 55px; + min-height: 0; + } +} + +@media only screen and (min-width: 475px) { + .gm-click-to-unmute { + left: calc(50% - 190px) !important; + } +} diff --git a/src/worker/FileUploaderWorker.js b/src/worker/FileUploaderWorker.js new file mode 100644 index 0000000..c23e66d --- /dev/null +++ b/src/worker/FileUploaderWorker.js @@ -0,0 +1,146 @@ +'use strict'; + +module.exports = function() { + const self = this; + this.socket = null; + this.token = null; + this.hasError = false; + this.isUploading = false; + this.uploadedSize = 0; + this.file = null; + this.address = null; + this.MEGABYTE = 1000 * 1000; + + self.getChunkSize = function(fileSize) { + /* + * The minimum upload size of chunk is 5MB. + * If we are uploading a "big" file, we are uploading 10% by 10%. + * The maximum chunk size is 75MB to avoid "out of memory" errors on PaaS. + */ + const minimum = 5 * self.MEGABYTE; + const maximum = 75 * self.MEGABYTE; + return Math.max(minimum, Math.min(0.1 * fileSize, maximum)); + }; + + self.onOpen = function() { + const tokenRequest = { + type: 'token', + token: self.token, + }; + self.socket.send(JSON.stringify(tokenRequest)); + }; + + self.onClose = function() { + setTimeout(function() { + self.connect(self.address); + }, 1000); + }; + + self.connect = function(address) { + self.socket = new WebSocket(address); + self.socket.binaryType = 'arraybuffer'; + self.socket.onopen = self.onOpen; + self.socket.onerror = self.onFailure; + self.socket.onmessage = self.onSocketMsg; + self.socket.onclose = self.onClose; + }; + + self.onFailure = function() { + const msg = { + type: 'FILE_UPLOAD', + code: 'FAIL', + }; + self.isUploading = false; + postMessage(msg); + }; + + self.uploadData = function(event) { + if (self.hasError === false) { + self.socket.send(event.target.result, {binary: true}); + } + }; + + self.onSocketMsg = function(evt) { + const msg = JSON.parse(evt.data); + + if (msg.type === 'FILE_UPLOAD') { + switch (msg.code) { + case 'NEXT': { + if (self.uploadedSize < self.file.size) { + const chunkLength = self.getChunkSize(self.file.size); + let blob; + const reader = new FileReader(); + reader.onload = self.uploadData; + reader.onabort = self.onFailure; + reader.onerror = self.onFailure; + + if (self.file.size - self.uploadedSize > chunkLength) { + blob = self.file.slice(self.uploadedSize, self.uploadedSize + chunkLength); + self.uploadedSize += chunkLength; + } else { + blob = self.file.slice(self.uploadedSize); + self.uploadedSize = self.file.size; + } + reader.readAsArrayBuffer(blob); + } else { + const status = { + type: 'FILE_UPLOAD', + 'done': true, + }; + self.socket.send(JSON.stringify(status)); + self.isUploading = false; + } + break; + } + case 'PROGRESS': + postMessage(msg); + break; + case 'SUCCESS': + postMessage(msg); + break; + case 'FAIL': + self.hasError = true; + postMessage(msg); + break; + default: + break; + } + } + }; + + self.onmessage = function(event) { + const msg = event.data; + + switch (msg.type) { + case 'address': + self.token = msg.token; + self.address = msg.fileUploadAddress; + self.connect(self.address); + break; + case 'close': + self.isUploading = false; + if (self.socket) { + self.socket.onclose = null; + self.socket.close(); + } + break; + case 'upload': + if (!self.isUploading) { + self.file = msg.file; + self.isUploading = true; + self.hasError = false; + self.uploadedSize = 0; + + const data = { + type: 'FILE_UPLOAD', + 'name': self.file.name, + 'size': self.file.size, + }; + self.socket.send(JSON.stringify(data)); + } + break; + default: + break; + } + }; +}; diff --git a/tests/config.js b/tests/config.js new file mode 100644 index 0000000..6529c4a --- /dev/null +++ b/tests/config.js @@ -0,0 +1,9 @@ +'use strict'; + +module.exports = { + clearMocks: true, + reporters: ['default', 'jest-junit'], + testMatch: [ + '**/?(*.)+(test).js' + ] +}; diff --git a/tests/mocks/GenymotionInstance.js b/tests/mocks/GenymotionInstance.js new file mode 100644 index 0000000..6fbc748 --- /dev/null +++ b/tests/mocks/GenymotionInstance.js @@ -0,0 +1,68 @@ +'use strict'; + +const Original = require('../../src/GenymotionInstance'); + +module.exports = class GenymotionInstance extends Original { + constructor(options) { + document.body.innerHTML = ` +
+
+
+ +
+
+
+
    +
+
+
+
+
`; + + window.adapter = { + browserDetails: { + browser: 'test' + } + }; + + navigator.mediaDevices = { + getUserMedia: jest.fn().mockReturnValue(Promise.resolve(null)) + }; + + super(document.body, options || {}); + this.outgoingMessages = []; + } + + /** + * Send event to the instance through the Websocket connection. + * + * @param {Object} event Event to send. + */ + sendEvent(event) { + this.outgoingMessages.push(event); + } + + /** + * Add a local stream and send it through SDP renegotiation. + */ + addLocalStream() { + + } + + /** + * Remove a local stream and stop sending it through SDP renegotiation. + */ + removeLocalStream() { + + } + + /** + * Reconfigure & setup the peer-to-peer connection (SDP). + * Can be used anytime to renegotiate the SDP if necessary. + */ + renegotiateWebRTCConnection() { + + } +}; diff --git a/tests/unit/battery.test.js b/tests/unit/battery.test.js new file mode 100644 index 0000000..04b50d1 --- /dev/null +++ b/tests/unit/battery.test.js @@ -0,0 +1,181 @@ +'use strict'; + +const Battery = require('../../src/plugins/Battery'); +const Instance = require('../mocks/GenymotionInstance'); + +let battery; +let instance; +let plugin; + +describe('Battery Plugin', () => { + beforeEach(() => { + instance = new Instance(); + battery = new Battery(instance, {}); + plugin = document.getElementsByClassName('gm-battery-plugin')[0]; + }); + + describe('api', () => { + test('exposes a high level constructor', () => { + expect(typeof Battery).toBe('function'); + }); + }); + + describe('UI', () => { + beforeEach(() => { + instance = new Instance(); + battery = new Battery(instance, { + BATTERY_TITLE: 'TEST BATTERY PLUGIN TITLE', + BATTERY_CHARGE_LEVEL: 'TEST BATTERY PLUGIN CHARGE LEVEL', + BATTERY_CHARGE_STATE: 'TEST BATTERY PLUGIN CHARGE STATE' + }); + plugin = document.getElementsByClassName('gm-battery-plugin')[0]; + }); + + test('is initialized properly at construct', () => { + // Widget + expect(document.getElementsByClassName('gm-battery-plugin')).toHaveLength(1); + // Toolbar button + expect(document.getElementsByClassName('gm-battery-button')).toHaveLength(1); + }); + + test('has default values', () => { + expect(battery.chargingInput.checked).toBeTruthy(); + expect(Number(battery.chargeSlider.value)).toBe(50); + expect(Number(battery.chargeInput.value)).toBe(50); + }); + + test('has translations', () => { + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST BATTERY PLUGIN TITLE')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST BATTERY PLUGIN CHARGE LEVEL')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST BATTERY PLUGIN CHARGE STATE')); + }); + }); + + describe('incoming events', () => { + let statusMock; + let levelMock; + + beforeEach(() => { + statusMock = jest.spyOn(battery, 'updateUIBatteryChargingState'); + levelMock = jest.spyOn(battery, 'onBatteryLevelChange'); + }); + + afterEach(() => { + statusMock.mockRestore(); + levelMock.mockRestore(); + }); + + test('BATTERY_STATUS', () => { + instance.emit('BATTERY_STATUS', 'jean-michel'); // Invalid value (=== charging) + expect(battery.chargingInput.checked).toBeTruthy(); + + instance.emit('BATTERY_STATUS', 'false'); // Discharging + expect(battery.chargingInput.checked).toBeFalsy(); + + instance.emit('BATTERY_STATUS', 'true'); // Charging + expect(battery.chargingInput.checked).toBeTruthy(); + }); + + test('BATTERY_LEVEL', () => { + instance.emit('BATTERY_LEVEL', 'jean-michel'); // Invalid value + expect(Number(battery.chargeSlider.value)).toBe(50); + expect(Number(battery.chargeInput.value)).toBe(50); + + instance.emit('BATTERY_LEVEL', '69'); // Nice + expect(Number(battery.chargeSlider.value)).toBe(69); + expect(Number(battery.chargeInput.value)).toBe(69); + + instance.emit('BATTERY_LEVEL', '666'); // Overflow + expect(Number(battery.chargeSlider.value)).toBe(100); + expect(Number(battery.chargeInput.value)).toBe(100); + + instance.emit('BATTERY_LEVEL', '-420'); // Underflow + expect(Number(battery.chargeSlider.value)).toBe(0); + expect(Number(battery.chargeInput.value)).toBe(0); + }); + + test('battery', () => { + instance.emit('battery', 'jean-michel'); // Bad format + expect(levelMock).not.toHaveBeenCalled(); + expect(statusMock).not.toHaveBeenCalled(); + + instance.emit('battery', 'state mode badstate badvalue'); // Bad state and value + expect(levelMock).toHaveBeenLastCalledWith('badvalue'); + expect(statusMock).toHaveBeenLastCalledWith(true); + expect(battery.chargingInput.checked).toBeTruthy(); + expect(Number(battery.chargeSlider.value)).toBe(50); + expect(Number(battery.chargeInput.value)).toBe(50); + + instance.emit('battery', 'state mode badstate 69'); // Bad state + expect(levelMock).toHaveBeenLastCalledWith('69'); + expect(statusMock).toHaveBeenLastCalledWith(true); + expect(battery.chargingInput.checked).toBeTruthy(); + expect(Number(battery.chargeSlider.value)).toBe(69); + expect(Number(battery.chargeInput.value)).toBe(69); + + instance.emit('battery', 'state mode discharging badlevel'); // Bad value + expect(levelMock).toHaveBeenLastCalledWith('badlevel'); + expect(statusMock).toHaveBeenLastCalledWith(false); + expect(battery.chargingInput.checked).toBeFalsy(); + expect(Number(battery.chargeSlider.value)).toBe(69); // Previous value + expect(Number(battery.chargeInput.value)).toBe(69); // Previous value + + instance.emit('battery', 'state mode charging 42'); // Good state and value + expect(levelMock).toHaveBeenLastCalledWith('42'); + expect(statusMock).toHaveBeenLastCalledWith(true); + expect(battery.chargingInput.checked).toBeTruthy(); + expect(Number(battery.chargeSlider.value)).toBe(42); + expect(Number(battery.chargeInput.value)).toBe(42); + }); + }); + + describe('outgoing events', () => { + let sendEventSpy; + + beforeEach(() => { + sendEventSpy = jest.spyOn(instance, 'sendEvent'); + }); + + afterEach(() => { + sendEventSpy.mockRestore(); + }); + + test('battery level input', () => { + battery.chargeInput.value = 69; // nice + battery.chargeInput.dispatchEvent(new Event('input')); + + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({ + channel: 'battery', messages: [ + 'set state level 69', + 'set state status charging', + ], + }); + }); + + test('battery level slider', () => { + battery.chargeSlider.value = 42; + battery.chargeSlider.dispatchEvent(new Event('change')); + + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({ + channel: 'battery', messages: [ + 'set state level 42', + 'set state status charging', + ], + }); + }); + + test('battery state', () => { + battery.chargingInput.click(); + + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({ + channel: 'battery', messages: [ + 'set state level 50', + 'set state status discharging', + ], + }); + }); + }); +}); diff --git a/tests/unit/buttonsevent.test.js b/tests/unit/buttonsevent.test.js new file mode 100644 index 0000000..1bf8f89 --- /dev/null +++ b/tests/unit/buttonsevent.test.js @@ -0,0 +1,236 @@ +'use strict'; + +const ButtonsEvents = require('../../src/plugins/ButtonsEvents'); +const Instance = require('../mocks/GenymotionInstance'); + +let instance; + +describe('ButtonsEvents Plugin', () => { + beforeEach(() => { + instance = new Instance({ + rotation: true, + volume: true, + navbar: true, + power: true + }); + new ButtonsEvents(instance, {}, false); + }); + + describe('api', () => { + test('exposes a high level constructor', () => { + expect(typeof ButtonsEvents).toBe('function'); + }); + }); + + describe('UI', () => { + test('is initialized properly at construct', () => { + instance = new Instance({ + rotation: true, + volume: true, + navbar: true, + power: true + }); + new ButtonsEvents(instance, {}, false); + + // Toolbar buttons + expect(document.getElementsByClassName('gm-rotate')).toHaveLength(1); + expect(document.getElementsByClassName('gm-sound-down')).toHaveLength(1); + expect(document.getElementsByClassName('gm-sound-up')).toHaveLength(1); + expect(document.getElementsByClassName('gm-recent')).toHaveLength(1); + expect(document.getElementsByClassName('gm-home')).toHaveLength(1); + expect(document.getElementsByClassName('gm-back')).toHaveLength(1); + expect(document.getElementsByClassName('gm-power')).toHaveLength(1); + }); + + test('handles instance options', () => { + instance = new Instance({ + rotation: false, + volume: null, + }); + new ButtonsEvents(instance, {}, false); + + // Toolbar buttons + expect(document.getElementsByClassName('gm-rotate')).toHaveLength(0); + expect(document.getElementsByClassName('gm-sound-down')).toHaveLength(0); + expect(document.getElementsByClassName('gm-sound-up')).toHaveLength(0); + expect(document.getElementsByClassName('gm-recent')).toHaveLength(0); + expect(document.getElementsByClassName('gm-home')).toHaveLength(0); + expect(document.getElementsByClassName('gm-back')).toHaveLength(0); + expect(document.getElementsByClassName('gm-power')).toHaveLength(0); + }); + + test('has translations', () => { + instance = new Instance({ + rotation: true, + volume: true, + navbar: true, + power: true + }); + new ButtonsEvents(instance, { + BUTTONS_ROTATE: 'TEST BUTTONS EVENTS ROTATE BUTTON', + BUTTONS_SOUND_DOWN: 'TEST BUTTONS EVENTS SOUND_DOWN BUTTON', + BUTTONS_SOUND_UP: 'TEST BUTTONS EVENTS SOUND_UP BUTTON', + BUTTONS_RECENT_APPS: 'TEST BUTTONS EVENTS RECENT_APPS BUTTON', + BUTTONS_HOME: 'TEST BUTTONS EVENTS HOME BUTTON', + BUTTONS_BACK: 'TEST BUTTONS EVENTS BACK BUTTON', + BUTTONS_POWER: 'TEST BUTTONS EVENTS POWER BUTTON' + }, false); + + // Toolbar buttons + const plugin = document.body; + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST BUTTONS EVENTS ROTATE BUTTON')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST BUTTONS EVENTS SOUND_DOWN BUTTON')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST BUTTONS EVENTS SOUND_UP BUTTON')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST BUTTONS EVENTS RECENT_APPS BUTTON')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST BUTTONS EVENTS HOME BUTTON')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST BUTTONS EVENTS BACK BUTTON')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST BUTTONS EVENTS POWER BUTTON')); + }); + }); + + describe('outgoing events', () => { + let sendEventSpy; + + beforeEach(() => { + sendEventSpy = jest.spyOn(instance, 'sendEvent'); + }); + + afterEach(() => { + sendEventSpy.mockRestore(); + }); + + test('rotation', () => { + const button = document.getElementsByClassName('gm-rotate')[0]; + + button.dispatchEvent(new Event('mousedown')); + button.dispatchEvent(new Event('mouseup')); + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({ + type: 'ROTATE' + }); + }); + + test('volume up', () => { + const button = document.getElementsByClassName('gm-sound-up')[0]; + + button.dispatchEvent(new Event('mousedown')); + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({ + type: 'KEYBOARD_PRESS', keycode: parseInt('0x01000072'), keychar: '0\n' + }); + + button.dispatchEvent(new Event('mouseup')); + expect(sendEventSpy).toHaveBeenCalledTimes(2); + expect(instance.outgoingMessages[1]).toEqual({ + type: 'KEYBOARD_RELEASE', keycode: parseInt('0x01000072'), keychar: '0\n' + }); + }); + + test('volume down', () => { + const button = document.getElementsByClassName('gm-sound-down')[0]; + + button.dispatchEvent(new Event('mousedown')); + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({ + type: 'KEYBOARD_PRESS', keycode: parseInt('0x01000070'), keychar: '0\n' + }); + + button.dispatchEvent(new Event('mouseup')); + expect(sendEventSpy).toHaveBeenCalledTimes(2); + expect(instance.outgoingMessages[1]).toEqual({ + type: 'KEYBOARD_RELEASE', keycode: parseInt('0x01000070'), keychar: '0\n' + }); + }); + + test('recent apps', () => { + const button = document.getElementsByClassName('gm-recent')[0]; + + button.dispatchEvent(new Event('mousedown')); + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({ + type: 'KEYBOARD_PRESS', keycode: parseInt('0x010000be'), keychar: '0\n' + }); + + button.dispatchEvent(new Event('mouseup')); + expect(sendEventSpy).toHaveBeenCalledTimes(2); + expect(instance.outgoingMessages[1]).toEqual({ + type: 'KEYBOARD_RELEASE', keycode: parseInt('0x010000be'), keychar: '0\n' + }); + }); + + test('home - default', () => { + const button = document.getElementsByClassName('gm-home')[0]; + + button.dispatchEvent(new Event('mousedown')); + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({ + type: 'KEYBOARD_PRESS', keycode: parseInt('0x01000010'), keychar: '0\n' + }); + + button.dispatchEvent(new Event('mouseup')); + expect(sendEventSpy).toHaveBeenCalledTimes(2); + expect(instance.outgoingMessages[1]).toEqual({ + type: 'KEYBOARD_RELEASE', keycode: parseInt('0x01000010'), keychar: '0\n' + }); + }); + + test('home - translated', () => { + instance = new Instance({ + navbar: true + }); + new ButtonsEvents(instance, {}, true); + const button = document.getElementsByClassName('gm-home')[0]; + sendEventSpy = jest.spyOn(instance, 'sendEvent'); + + button.dispatchEvent(new Event('mousedown')); + expect(sendEventSpy).toHaveBeenCalledTimes(2); + expect(instance.outgoingMessages[0]).toEqual({ + type: 'KEYBOARD_PRESS', keycode: parseInt('0x01000022'), keychar: '' + }); + expect(instance.outgoingMessages[1]).toEqual({ + type: 'KEYBOARD_PRESS', keycode: parseInt('0x01000005'), keychar: '' + }); + + button.dispatchEvent(new Event('mouseup')); + expect(sendEventSpy).toHaveBeenCalledTimes(4); + expect(instance.outgoingMessages[2]).toEqual({ + type: 'KEYBOARD_RELEASE', keycode: parseInt('0x01000005'), keychar: '' + }); + expect(instance.outgoingMessages[3]).toEqual({ + type: 'KEYBOARD_RELEASE', keycode: parseInt('0x01000022'), keychar: '' + }); + }); + + test('back', () => { + const button = document.getElementsByClassName('gm-back')[0]; + + button.dispatchEvent(new Event('mousedown')); + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({ + type: 'KEYBOARD_PRESS', keycode: parseInt('0x01000061'), keychar: '0\n' + }); + + button.dispatchEvent(new Event('mouseup')); + expect(sendEventSpy).toHaveBeenCalledTimes(2); + expect(instance.outgoingMessages[1]).toEqual({ + type: 'KEYBOARD_RELEASE', keycode: parseInt('0x01000061'), keychar: '0\n' + }); + }); + + test('power', () => { + const button = document.getElementsByClassName('gm-power')[0]; + + button.dispatchEvent(new Event('mousedown')); + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({ + type: 'KEYBOARD_PRESS', keycode: parseInt('0x0100010b'), keychar: '0\n' + }); + + button.dispatchEvent(new Event('mouseup')); + expect(sendEventSpy).toHaveBeenCalledTimes(2); + expect(instance.outgoingMessages[1]).toEqual({ + type: 'KEYBOARD_RELEASE', keycode: parseInt('0x0100010b'), keychar: '0\n' + }); + }); + }); +}); diff --git a/tests/unit/camera.test.js b/tests/unit/camera.test.js new file mode 100644 index 0000000..af3c10b --- /dev/null +++ b/tests/unit/camera.test.js @@ -0,0 +1,105 @@ +'use strict'; + +jest.mock('loglevel'); + +const Camera = require('../../src/plugins/Camera'); +const Instance = require('../mocks/GenymotionInstance'); + +let camera; +let instance; + +describe('Camera Plugin', () => { + beforeEach(() => { + instance = new Instance({ + rotation: true, + volume: true, + navbar: true, + power: true + }); + camera = new Camera(instance, false); + }); + + describe('api', () => { + test('exposes a high level constructor', () => { + expect(typeof Camera).toBe('function'); + }); + }); + + describe('UI', () => { + beforeEach(() => { + instance = new Instance(); + new Camera(instance, { + CAMERA_TITLE: 'TEST CAMERA PLUGIN BUTTON TITLE' + }); + }); + + test('is initialized properly at construct', () => { + // Toolbar button + expect(document.getElementsByClassName('gm-camera-button')).toHaveLength(1); + }); + + test('has translations', () => { + const plugin = document.body; + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST CAMERA PLUGIN BUTTON TITLE')); + }); + }); + + describe('camera', () => { + let startSpy; + let stopSpy; + + beforeEach(() => { + startSpy = jest.spyOn(camera, 'startStreaming'); + stopSpy = jest.spyOn(camera, 'stopStreaming'); + + camera.onVideoStreamError = jest.fn(); + instance.addLocalStream = jest.fn(); + }); + + afterEach(() => { + startSpy.mockRestore(); + stopSpy.mockRestore(); + navigator.mediaDevices.getUserMedia.mockRestore(); + camera.onVideoStreamError.mockRestore(); + instance.addLocalStream.mockRestore(); + }); + + it('can be toggled on', (done) => { + const plugin = document.getElementsByClassName('gm-camera-button')[0]; + + instance.addLocalStream.mockImplementationOnce(() => { + expect(navigator.mediaDevices.getUserMedia).toHaveBeenCalledTimes(1); + expect(startSpy).toHaveBeenCalledTimes(1); + expect(stopSpy).toHaveBeenCalledTimes(0); + expect(camera.onVideoStreamError).toHaveBeenCalledTimes(0); + done(); + }); + + plugin.click(); + }); + + it('can be toggled off', () => { + const plugin = document.getElementsByClassName('gm-camera-button')[0]; + + camera.streaming = true; + plugin.click(); + expect(startSpy).toHaveBeenCalledTimes(0); + expect(stopSpy).toHaveBeenCalledTimes(1); + }); + + it('handle mediaDevices errors', (done) => { + const plugin = document.getElementsByClassName('gm-camera-button')[0]; + + camera.onVideoStreamError.mockImplementationOnce(() => { + expect(navigator.mediaDevices.getUserMedia).toHaveBeenCalledTimes(1); + expect(startSpy).toHaveBeenCalledTimes(1); + expect(stopSpy).toHaveBeenCalledTimes(0); + expect(instance.addLocalStream).toHaveBeenCalledTimes(0); + expect(camera.onVideoStreamError).toHaveBeenCalledTimes(1); + done(); + }); + navigator.mediaDevices.getUserMedia.mockReturnValueOnce(Promise.reject(null)); + plugin.click(); + }); + }); +}); diff --git a/tests/unit/clipboard.test.js b/tests/unit/clipboard.test.js new file mode 100644 index 0000000..657d969 --- /dev/null +++ b/tests/unit/clipboard.test.js @@ -0,0 +1,110 @@ +'use strict'; + +jest.mock('loglevel'); + +const Clipboard = require('../../src/plugins/Clipboard'); +const Instance = require('../mocks/GenymotionInstance'); + +let clipboard; +let instance; +let plugin; + +describe('Clipboard Plugin', () => { + beforeEach(() => { + instance = new Instance(); + clipboard = new Clipboard(instance, {}); + plugin = document.getElementsByClassName('gm-clipboard-plugin')[0]; + }); + + describe('api', () => { + test('exposes a high level constructor', () => { + expect(typeof Clipboard).toBe('function'); + }); + }); + + describe('UI', () => { + beforeEach(() => { + instance = new Instance(); + clipboard = new Clipboard(instance, { + CLIPBOARD_TITLE: 'TEST CLIPBOARD PLUGIN TITLE', + CLIPBOARD_COPIED: 'TEST CLIPBOARD COPIED TO CLIPBOARD' + }); + plugin = document.getElementsByClassName('gm-clipboard-plugin')[0]; + }); + + test('is initialized properly at construct', () => { + // Widget + expect(document.getElementsByClassName('gm-clipboard-plugin')).toHaveLength(1); + // Toolbar button + expect(document.getElementsByClassName('gm-clipboard-button')).toHaveLength(1); + }); + + test('has default values', () => { + expect(clipboard.clipboardInput.value).toBe(''); + }); + + test('has translations', () => { + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST CLIPBOARD PLUGIN TITLE')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST CLIPBOARD COPIED TO CLIPBOARD')); + }); + + test('reflects internal clipboard state when displayed', () => { + const button = document.getElementsByClassName('gm-clipboard-button')[0]; + + clipboard.clipboard = 'test value'; + button.click(); + expect(clipboard.clipboardInput.value).toBe('test value'); + }); + }); + + describe('incoming events', () => { + test('CLIPBOARD', () => { + instance.emit('CLIPBOARD', 'test value'); + expect(clipboard.clipboard).toBe('test value'); + }); + + test('framework', () => { + instance.emit('framework', 'clipboard too many arguments'); + expect(clipboard.clipboard).toBe(''); + + instance.emit('framework', 'clipboard missingparam'); + expect(clipboard.clipboard).toBe(''); + + instance.emit('framework', 'unrelevant channel'); + expect(clipboard.clipboard).toBe(''); + + instance.emit('framework', 'clipboard from_android badvalue'); // Bad value + expect(clipboard.clipboard).toBe(''); + + instance.emit('framework', 'clipboard from_android dGVzdCB2YWx1ZQ=='); + expect(clipboard.clipboard).toBe('test value'); + }); + }); + + describe('outgoing events', () => { + let sendEventSpy; + + beforeEach(() => { + sendEventSpy = jest.spyOn(instance, 'sendEvent'); + }); + + afterEach(() => { + sendEventSpy.mockRestore(); + }); + + test('clipboard value', () => { + const button = document.getElementsByClassName('gm-clipboard-button')[0]; + + clipboard.clipboard = 'test value'; + button.click(); // Open + button.click(); // Close + + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({ + channel: 'framework', messages: [ + 'set_device_clipboard dGVzdCB2YWx1ZQ==', + ], + }); + }); + }); +}); diff --git a/tests/unit/fileupload.test.js b/tests/unit/fileupload.test.js new file mode 100644 index 0000000..95f313e --- /dev/null +++ b/tests/unit/fileupload.test.js @@ -0,0 +1,293 @@ +'use strict'; + +const FileUpload = require('../../src/plugins/FileUpload'); +const Instance = require('../mocks/GenymotionInstance'); + +let uploader; +let instance; +let plugin; + +describe('FileUpload Plugin', () => { + beforeEach(() => { + instance = new Instance(); + uploader = new FileUpload(instance, { + UPLOADER_INSTALLING: 'TEST UPLOADER PLUGIN INSTALLING...' + }); + plugin = document.getElementsByClassName('gm-uploader-plugin')[0]; + }); + + describe('api', () => { + test('exposes a high level constructor', () => { + expect(typeof FileUpload).toBe('function'); + }); + + it('should attach ondragover, ondragenter, and ondragleave to root', () => { + expect(typeof instance.videoWrapper.ondragover).toBe('function'); + expect(typeof instance.videoWrapper.ondragleave).toBe('function'); + expect(typeof instance.videoWrapper.ondragenter).toBe('function'); + }); + }); + + describe('UI', () => { + beforeEach(() => { + instance = new Instance(); + uploader = new FileUpload(instance, { + UPLOADER_TITLE: 'TEST UPLOADER PLUGIN TITLE', + UPLOADER_HOME_TITLE: 'TEST UPLOADER PLUGIN HOME TITLE', + UPLOADER_DISCLAIMER: 'TEST UPLOADER PLUGIN DISCLAIMER', + UPLOADER_INPROGRESS: 'TEST UPLOADER PLUGIN IN PROGRESS', + UPLOADER_SUCCESS: 'TEST UPLOADER PLUGIN SUCCESS', + UPLOADER_FAILURE: 'TEST UPLOADER PLUGIN FAILURE' + + }); + plugin = document.getElementsByClassName('gm-uploader-plugin')[0]; + }); + + test('is initialized properly at construct', () => { + // Widget + expect(document.getElementsByClassName('gm-uploader-plugin')).toHaveLength(1); + // Toolbar button + expect(document.getElementsByClassName('gm-uploader-button')).toHaveLength(1); + }); + + test('has translations', () => { + uploader.displayStep('homeScreen'); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST UPLOADER PLUGIN HOME TITLE')); + uploader.displayStep('disclaimerScreen'); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST UPLOADER PLUGIN DISCLAIMER')); + uploader.displayStep('uploadScreen'); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST UPLOADER PLUGIN IN PROGRESS')); + uploader.displayStep('successScreen'); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST UPLOADER PLUGIN SUCCESS')); + uploader.displayStep('errorScreen'); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST UPLOADER PLUGIN FAILURE')); + }); + + test('allows access to disclaimer on right conditions', () => { + uploader.displayStep('homeScreen'); + const displayStep = jest.spyOn(uploader, 'displayStep'); + + // Not allowed by default + uploader.installButton.click(); + expect(displayStep).toHaveBeenCalledTimes(0); + + // Already installed + uploader.opengappsInstalled = true; + uploader.capabilityAvailable = true; + uploader.installButton.click(); + expect(displayStep).toHaveBeenCalledTimes(0); + + // Not available + uploader.opengappsInstalled = false; + uploader.capabilityAvailable = false; + uploader.installButton.click(); + expect(displayStep).toHaveBeenCalledTimes(0); + + // Available + uploader.opengappsInstalled = false; + uploader.capabilityAvailable = true; + uploader.installButton.click(); + expect(displayStep).toHaveBeenNthCalledWith(1, 'disclaimerScreen'); + }); + + test('sets proper step on toggle', () => { + uploader.displayStep('homeScreen'); + uploader.toggleWidget(); + uploader.toggleWidget(); + expect(uploader.currentStep).toEqual('homeScreen'); + uploader.displayStep('disclaimerScreen'); + uploader.toggleWidget(); + uploader.toggleWidget(); + expect(uploader.currentStep).toEqual('disclaimerScreen'); + uploader.displayStep('uploadScreen'); + uploader.toggleWidget(); + uploader.toggleWidget(); + expect(uploader.currentStep).toEqual('uploadScreen'); + uploader.displayStep('successScreen'); + uploader.toggleWidget(); + uploader.toggleWidget(); + expect(uploader.currentStep).toEqual('homeScreen'); + uploader.displayStep('errorScreen'); + uploader.toggleWidget(); + uploader.toggleWidget(); + expect(uploader.currentStep).toEqual('homeScreen'); + }); + + test('Dont force show on success', () => { + uploader.flashing = false; + uploader.displayStep('uploadScreen'); + expect(document.getElementsByClassName('gm-hidden').length).toEqual(1); + instance.emit('SYSTEM_PATCHER_LAST_RESULT', 'success'); + expect(document.getElementsByClassName('gm-hidden').length).toEqual(1); + }); + + test('dont force show on error', () => { + uploader.flashing = false; + uploader.displayStep('uploadScreen'); + expect(document.getElementsByClassName('gm-hidden').length).toEqual(1); + instance.emit('SYSTEM_PATCHER_LAST_RESULT', 'install_error'); + expect(document.getElementsByClassName('gm-hidden').length).toEqual(1); + }); + + test('force show on opengapps success', () => { + uploader.flashing = true; + uploader.displayStep('uploadScreen'); + expect(document.getElementsByClassName('gm-hidden').length).toEqual(1); + instance.emit('SYSTEM_PATCHER_LAST_RESULT', 'success'); + expect(document.getElementsByClassName('gm-hidden').length).toEqual(0); + }); + + test('force show on opengapps error', () => { + uploader.flashing = true; + uploader.displayStep('uploadScreen'); + expect(document.getElementsByClassName('gm-hidden').length).toEqual(1); + instance.emit('SYSTEM_PATCHER_LAST_RESULT', 'install_error'); + expect(document.getElementsByClassName('gm-hidden').length).toEqual(0); + }); + }); + + describe('incoming events', () => { + describe('SYSTEM_PATCHER_STATUS', () => { + test('downloading', () => { + uploader.displayStep('uploadScreen'); + const textProgress = document.getElementsByClassName('gm-upload-in-progress-txt-percent')[0]; + + instance.emit('SYSTEM_PATCHER_STATUS', 'downloading something'); // Not enough parameters + expect(textProgress.innerHTML).toBe(''); + + instance.emit('SYSTEM_PATCHER_STATUS', 'downloading 69 100'); + expect(textProgress.innerHTML).toBe('69%'); // Nice + }); + + test('installing', () => { + uploader.displayStep('uploadScreen'); + const textProgress = document.getElementsByClassName('gm-upload-in-progress-txt-progress')[0]; + + instance.emit('SYSTEM_PATCHER_STATUS', 'installing'); + expect(textProgress.innerHTML).toBe('TEST UPLOADER PLUGIN INSTALLING...'); + }); + + test('ready', () => { + const updateOpenGAppsStatus = jest.spyOn(uploader, 'updateOpenGAppsStatus'); + const sendEventSpy = jest.spyOn(instance, 'sendEvent'); + + instance.emit('SYSTEM_PATCHER_STATUS', 'ready'); // Not enough parameters + expect(updateOpenGAppsStatus).toHaveBeenCalledTimes(0); + + instance.emit('SYSTEM_PATCHER_STATUS', 'ready something'); + expect(updateOpenGAppsStatus).toHaveBeenCalledTimes(0); + + // Asumes uploader.flashing = false, default + instance.emit('SYSTEM_PATCHER_STATUS', 'ready opengapps'); + expect(updateOpenGAppsStatus).toHaveBeenCalledTimes(1); + expect(sendEventSpy).toHaveBeenCalledTimes(0); + + uploader.flashing = true; + instance.emit('SYSTEM_PATCHER_STATUS', 'ready opengapps'); + expect(updateOpenGAppsStatus).toHaveBeenCalledTimes(2); + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({ + channel: 'systempatcher', messages: [ + 'notify last_result' + ] + }); + }); + }); + + test('SYSTEM_PATCHER_LAST_RESULT', () => { + const displayStep = jest.spyOn(uploader, 'displayStep'); + + instance.emit('SYSTEM_PATCHER_LAST_RESULT', 'success'); + expect(displayStep).toHaveBeenNthCalledWith(1, 'successScreen'); + + instance.emit('SYSTEM_PATCHER_LAST_RESULT', 'unavailable'); + expect(displayStep).toHaveBeenNthCalledWith(2, 'errorScreen'); + + instance.emit('SYSTEM_PATCHER_LAST_RESULT', 'network_error'); + expect(displayStep).toHaveBeenNthCalledWith(3, 'errorScreen'); + + instance.emit('SYSTEM_PATCHER_LAST_RESULT', 'corrupted_archive'); + expect(displayStep).toHaveBeenNthCalledWith(4, 'errorScreen'); + + instance.emit('SYSTEM_PATCHER_LAST_RESULT', 'install_error'); + expect(displayStep).toHaveBeenNthCalledWith(5, 'errorScreen'); + + instance.emit('SYSTEM_PATCHER_LAST_RESULT', 'something'); + expect(displayStep).toHaveBeenCalledTimes(5); + + instance.emit('SYSTEM_PATCHER_LAST_RESULT', ''); + expect(displayStep).toHaveBeenCalledTimes(5); + }); + + test('systempatcher', () => { + const onSystemPatcherStatusEvent = jest.spyOn(uploader, 'onSystemPatcherStatusEvent'); + const onSystemPatcherLastResultEvent = jest.spyOn(uploader, 'onSystemPatcherLastResultEvent'); + + instance.emit('systempatcher', 'status some various params'); + expect(onSystemPatcherStatusEvent).toHaveBeenNthCalledWith(1, 'some various params'); + expect(onSystemPatcherLastResultEvent).toHaveBeenCalledTimes(0); + + instance.emit('systempatcher', 'last_result some various params'); + expect(onSystemPatcherStatusEvent).toHaveBeenCalledTimes(1); + expect(onSystemPatcherLastResultEvent).toHaveBeenCalledTimes(1, 'some various params'); + + instance.emit('systempatcher', 'unrelevant some various params'); + expect(onSystemPatcherStatusEvent).toHaveBeenCalledTimes(1); + expect(onSystemPatcherLastResultEvent).toHaveBeenCalledTimes(1); + }); + }); + + describe('outgoing events', () => { + let sendEventSpy; + + beforeEach(() => { + sendEventSpy = jest.spyOn(instance, 'sendEvent'); + }); + + afterEach(() => { + sendEventSpy.mockRestore(); + }); + + test('flash opengapps', () => { + uploader.displayStep('disclaimerScreen'); + const button = document.getElementsByClassName('gm-upload-main-bottom-buttons-right')[0]; + + button.click(); + + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({ + channel: 'systempatcher', messages: [ + 'install opengapps' + ] + }); + }); + + test('cancel flash opengapps', () => { + uploader.displayStep('uploadScreen'); + const button = document.getElementsByClassName('gm-upload-main-bottom-buttons-right')[0]; + + button.click(); + + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({ + channel: 'systempatcher', messages: [ + 'cancel' + ] + }); + }); + + test('reboot instance', () => { + uploader.displayStep('successScreen'); + const button = document.getElementsByClassName('gm-upload-success-button')[0]; + + button.click(); + + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({ + channel: 'systempatcher', messages: [ + 'reboot' + ] + }); + }); + }); +}); diff --git a/tests/unit/fullscreen.test.js b/tests/unit/fullscreen.test.js new file mode 100644 index 0000000..960257a --- /dev/null +++ b/tests/unit/fullscreen.test.js @@ -0,0 +1,25 @@ + +'use strict'; + +const FullScreen = require('../../src/plugins/Fullscreen'); +const Instance = require('../mocks/GenymotionInstance'); + +describe('FullScreen Plugin', () => { + beforeEach(() => { + const instance = new Instance(); + new FullScreen(instance); + }); + + describe('api', () => { + test('exposes a high level constructor', () => { + expect(typeof FullScreen).toBe('function'); + }); + }); + + describe('UI', () => { + test('is initialized properly at construct', () => { + // Toolbar button + expect(document.getElementsByClassName('gm-fullscreen-button')).toHaveLength(1); + }); + }); +}); diff --git a/tests/unit/gps.test.js b/tests/unit/gps.test.js new file mode 100644 index 0000000..251b8fd --- /dev/null +++ b/tests/unit/gps.test.js @@ -0,0 +1,352 @@ +'use strict'; + +jest.mock('loglevel'); + +const GPS = require('../../src/plugins/GPS'); +const Instance = require('../mocks/GenymotionInstance'); + +let gps; +let instance; +let controls; +let map; + +describe('GPS Plugin', () => { + beforeEach(() => { + instance = new Instance(); + gps = new GPS(instance, {}, true); + controls = document.getElementsByClassName('gm-gps-controls')[0]; + map = document.getElementsByClassName('gm-gps-mapview')[0]; + }); + + describe('api', () => { + test('exposes a high level constructor', () => { + expect(typeof GPS).toBe('function'); + }); + }); + + describe('UI', () => { + beforeEach(() => { + instance = new Instance(); + gps = new GPS(instance, { + GPS_TITLE: 'TEST GPS PLUGIN TITLE', + GPS_CANCEL: 'TEST GPS PLUGIN CANCEL', + GPS_CAPTURE: 'TEST GPS PLUGIN CAPTURE', + GPS_LATITUDE: 'TEST GPS PLUGIN LATITUDE', + GPS_LONGITUDE: 'TEST GPS PLUGIN LONGITUDE', + GPS_ALTITUDE: 'TEST GPS PLUGIN ALTITUDE', + GPS_ACCURACY: 'TEST GPS PLUGIN ACCURACY', + GPS_BEARING: 'TEST GPS PLUGIN BEARING', + GPS_SPEED: 'TEST GPS PLUGIN SPEED', + GPS_MAP: 'TEST GPS PLUGIN MAP', + GPS_GEOLOC: 'TEST GPS PLUGIN GEOLOC', + GPS_SUBMIT: 'TEST GPS PLUGIN SUBMIT', + GPS_GEOLOC_TOOLTIP: 'TEST GPS PLUGIN GEOLOC TOOLTIP', + GPS_NOGEOLOC_TOOLTIP: 'TEST GPS PLUGIN NOGEOLOC TOOLTIP' + }, true); + controls = document.getElementsByClassName('gm-gps-controls')[0]; + map = document.getElementsByClassName('gm-gps-mapview')[0]; + }); + + test('has no speed support by default', () => { + instance = new Instance(); + gps = new GPS(instance, {}); + expect(document.getElementsByClassName('gm-gps-speed')).toHaveLength(0); + }); + + test('is initialized properly at construct', () => { + // Widget views + expect(document.getElementsByClassName('gm-gps-controls')).toHaveLength(1); + expect(document.getElementsByClassName('gm-gps-mapview')).toHaveLength(1); + // Toolbar button + expect(document.getElementsByClassName('gm-gps-button')).toHaveLength(1); + }); + + test('has translations', () => { + expect(controls.innerHTML).toEqual(expect.stringContaining('TEST GPS PLUGIN TITLE')); + expect(controls.innerHTML).toEqual(expect.stringContaining('TEST GPS PLUGIN LATITUDE')); + expect(controls.innerHTML).toEqual(expect.stringContaining('TEST GPS PLUGIN LONGITUDE')); + expect(controls.innerHTML).toEqual(expect.stringContaining('TEST GPS PLUGIN ALTITUDE')); + expect(controls.innerHTML).toEqual(expect.stringContaining('TEST GPS PLUGIN ACCURACY')); + expect(controls.innerHTML).toEqual(expect.stringContaining('TEST GPS PLUGIN BEARING')); + expect(controls.innerHTML).toEqual(expect.stringContaining('TEST GPS PLUGIN SPEED')); + expect(controls.innerHTML).toEqual(expect.stringContaining('TEST GPS PLUGIN GEOLOC')); + expect(controls.innerHTML).toEqual(expect.stringContaining('TEST GPS PLUGIN SUBMIT')); + expect(controls.innerHTML).toEqual(expect.stringContaining('TEST GPS PLUGIN MAP')); + + expect(map.innerHTML).toEqual(expect.stringContaining('TEST GPS PLUGIN CAPTURE')); + expect(map.innerHTML).toEqual(expect.stringContaining('TEST GPS PLUGIN CANCEL')); + }); + + describe('field validation', () => { + const inputsInvalidValues = [ + ['gm-gps-latitude', 100], + ['gm-gps-longitude', -666], + ['gm-gps-altitude', 23456], + ['gm-gps-accuracy', -2], + ['gm-gps-bearing', 430], + ['gm-gps-speed', 400], + ]; + inputsInvalidValues.forEach(([field, value]) => { + test('button disabled', () => { + const fieldInput = document.getElementsByClassName(field)[0]; + const submitButton = document.getElementsByClassName('gm-gps-submit')[0]; + fieldInput.value = value; + fieldInput.dispatchEvent(new Event('keyup')); + + expect(fieldInput.classList.contains('gm-error')).toBeTruthy(); + expect(submitButton.disabled).toBeTruthy(); + }); + }); + }); + }); + + describe('incoming events', () => { + describe('gps', () => { + test('invalid messages', () => { + const setFieldValue = jest.spyOn(gps, 'setFieldValue'); + + instance.emit('gps', 'status'); + expect(setFieldValue).toHaveBeenCalledTimes(0); + + instance.emit('gps', 'jean-michel'); + expect(setFieldValue).toHaveBeenCalledTimes(0); + }); + + test('altitude', () => { + const setFieldValue = jest.spyOn(gps, 'setFieldValue'); + + instance.emit('gps', 'altitude'); // Missing value + expect(setFieldValue).toHaveBeenCalledTimes(0); + + instance.emit('gps', 'altitude jean-michel'); + expect(Number(document.getElementsByClassName('gm-gps-altitude')[0].value)).toBe(15.04444408); + instance.emit('gps', 'altitude -22666'); + expect(Number(document.getElementsByClassName('gm-gps-altitude')[0].value)).toBe(-10000); + instance.emit('gps', 'altitude 22666'); + expect(Number(document.getElementsByClassName('gm-gps-altitude')[0].value)).toBe(10000); + expect(setFieldValue).toHaveBeenCalledTimes(3); + + instance.emit('gps', 'altitude 0'); + expect(Number(document.getElementsByClassName('gm-gps-altitude')[0].value)).toBe(0); + instance.emit('gps', 'altitude -420'); + expect(Number(document.getElementsByClassName('gm-gps-altitude')[0].value)).toBe(-420); + instance.emit('gps', 'altitude 69'); // Nice + expect(Number(document.getElementsByClassName('gm-gps-altitude')[0].value)).toBe(69); + expect(setFieldValue).toHaveBeenCalledTimes(6); + }); + + test('latitude', () => { + const setFieldValue = jest.spyOn(gps, 'setFieldValue'); + + instance.emit('gps', 'latitude'); // Missing value + expect(setFieldValue).toHaveBeenCalledTimes(0); + + instance.emit('gps', 'latitude jean-michel'); + expect(Number(document.getElementsByClassName('gm-gps-latitude')[0].value)).toBe(65.9667); + instance.emit('gps', 'latitude -420'); + expect(Number(document.getElementsByClassName('gm-gps-latitude')[0].value)).toBe(-90); + instance.emit('gps', 'latitude 666'); + expect(Number(document.getElementsByClassName('gm-gps-latitude')[0].value)).toBe(90); + expect(setFieldValue).toHaveBeenCalledTimes(3); + + instance.emit('gps', 'latitude 0'); + expect(Number(document.getElementsByClassName('gm-gps-latitude')[0].value)).toBe(0); + instance.emit('gps', 'latitude -42'); + expect(Number(document.getElementsByClassName('gm-gps-latitude')[0].value)).toBe(-42); + instance.emit('gps', 'latitude 69'); // Nice + expect(Number(document.getElementsByClassName('gm-gps-latitude')[0].value)).toBe(69); + expect(setFieldValue).toHaveBeenCalledTimes(6); + }); + + test('longitude', () => { + const setFieldValue = jest.spyOn(gps, 'setFieldValue'); + + instance.emit('gps', 'longitude'); // Missing value + expect(setFieldValue).toHaveBeenCalledTimes(0); + + instance.emit('gps', 'longitude jean-michel'); + expect(Number(document.getElementsByClassName('gm-gps-longitude')[0].value)).toBe(-18.5333); + instance.emit('gps', 'longitude -420'); + expect(Number(document.getElementsByClassName('gm-gps-longitude')[0].value)).toBe(-180); + instance.emit('gps', 'longitude 666'); + expect(Number(document.getElementsByClassName('gm-gps-longitude')[0].value)).toBe(180); + expect(setFieldValue).toHaveBeenCalledTimes(3); + + instance.emit('gps', 'longitude 0'); + expect(Number(document.getElementsByClassName('gm-gps-longitude')[0].value)).toBe(0); + instance.emit('gps', 'longitude -123.45'); + expect(Number(document.getElementsByClassName('gm-gps-longitude')[0].value)).toBe(-123.45); + instance.emit('gps', 'longitude 69'); // Nice + expect(Number(document.getElementsByClassName('gm-gps-longitude')[0].value)).toBe(69); + expect(setFieldValue).toHaveBeenCalledTimes(6); + }); + + test('accuracy', () => { + const setFieldValue = jest.spyOn(gps, 'setFieldValue'); + + instance.emit('gps', 'accuracy'); // Missing value + expect(setFieldValue).toHaveBeenCalledTimes(0); + + instance.emit('gps', 'accuracy jean-michel'); + expect(Number(document.getElementsByClassName('gm-gps-accuracy')[0].value)).toBe(0); + instance.emit('gps', 'accuracy -666'); + expect(Number(document.getElementsByClassName('gm-gps-accuracy')[0].value)).toBe(0); + instance.emit('gps', 'accuracy 420'); + expect(Number(document.getElementsByClassName('gm-gps-accuracy')[0].value)).toBe(200); + expect(setFieldValue).toHaveBeenCalledTimes(3); + + instance.emit('gps', 'accuracy 42'); + expect(Number(document.getElementsByClassName('gm-gps-accuracy')[0].value)).toBe(42); + instance.emit('gps', 'accuracy 69'); // Nice + expect(Number(document.getElementsByClassName('gm-gps-accuracy')[0].value)).toBe(69); + expect(setFieldValue).toHaveBeenCalledTimes(5); + }); + + test('bearing', () => { + const setFieldValue = jest.spyOn(gps, 'setFieldValue'); + + instance.emit('gps', 'bearing'); // Missing value + expect(setFieldValue).toHaveBeenCalledTimes(0); + + instance.emit('gps', 'bearing jean-michel'); + expect(Number(document.getElementsByClassName('gm-gps-bearing')[0].value)).toBe(0); + instance.emit('gps', 'bearing -22666'); + expect(Number(document.getElementsByClassName('gm-gps-bearing')[0].value)).toBe(0); + instance.emit('gps', 'bearing 22666'); + expect(Number(document.getElementsByClassName('gm-gps-bearing')[0].value)).toBe(360); + expect(setFieldValue).toHaveBeenCalledTimes(3); + + instance.emit('gps', 'bearing 42'); + expect(Number(document.getElementsByClassName('gm-gps-bearing')[0].value)).toBe(42); + instance.emit('gps', 'bearing 69'); // Nice + expect(Number(document.getElementsByClassName('gm-gps-bearing')[0].value)).toBe(69); + expect(setFieldValue).toHaveBeenCalledTimes(5); + }); + + test('speed', () => { + const setFieldValue = jest.spyOn(gps, 'setFieldValue'); + + instance.emit('gps', 'speed'); // Missing value + expect(setFieldValue).toHaveBeenCalledTimes(0); + + instance.emit('gps', 'speed jean-michel'); + expect(Number(document.getElementsByClassName('gm-gps-speed')[0].value)).toBe(0); + instance.emit('gps', 'speed -22666'); + expect(Number(document.getElementsByClassName('gm-gps-speed')[0].value)).toBe(0); + instance.emit('gps', 'speed 300000000'); + expect(Number(document.getElementsByClassName('gm-gps-speed')[0].value)).toBe(399.99); + expect(setFieldValue).toHaveBeenCalledTimes(3); + + instance.emit('gps', 'speed 42'); + expect(Number(document.getElementsByClassName('gm-gps-speed')[0].value)).toBe(42); + instance.emit('gps', 'speed 69'); // Nice + expect(Number(document.getElementsByClassName('gm-gps-speed')[0].value)).toBe(69); + expect(setFieldValue).toHaveBeenCalledTimes(5); + }); + }); + }); + + describe('outgoing events', () => { + let sendEventSpy; + + beforeEach(() => { + sendEventSpy = jest.spyOn(instance, 'sendEvent'); + }); + + afterEach(() => { + sendEventSpy.mockRestore(); + }); + + test('invalid input value', () => { + document.getElementsByClassName('gm-gps-altitude')[0].value = 'jean-michel'; + document.getElementsByClassName('gm-gps-latitude')[0].value = 'jean-michel'; + document.getElementsByClassName('gm-gps-longitude')[0].value = 'jean-michel'; + document.getElementsByClassName('gm-gps-accuracy')[0].value = 'jean-michel'; + document.getElementsByClassName('gm-gps-bearing')[0].value = 'jean-michel'; + document.getElementsByClassName('gm-gps-speed')[0].value = 'jean-michel'; + document.getElementsByClassName('gm-gps-submit')[0].click(); + + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({ + channel: 'gps', messages: [ + 'set altitude 0', + 'set longitude 0', + 'set latitude 0', + 'set accuracy 0', + 'set bearing 0', + 'set speed 0', + 'enable' + ], + }); + }); + + test('min value', () => { + document.getElementsByClassName('gm-gps-altitude')[0].value = '-22666'; + document.getElementsByClassName('gm-gps-latitude')[0].value = '-420'; + document.getElementsByClassName('gm-gps-longitude')[0].value = '-666'; + document.getElementsByClassName('gm-gps-accuracy')[0].value = '-69'; + document.getElementsByClassName('gm-gps-bearing')[0].value = '-42'; + document.getElementsByClassName('gm-gps-speed')[0].value = '-42'; + document.getElementsByClassName('gm-gps-submit')[0].click(); + + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({ + channel: 'gps', messages: [ + 'set altitude -10000', + 'set longitude -180', + 'set latitude -90', + 'set accuracy 0', + 'set bearing 0', + 'set speed 0', + 'enable' + ], + }); + }); + + test('max value', () => { + document.getElementsByClassName('gm-gps-altitude')[0].value = '22666'; + document.getElementsByClassName('gm-gps-latitude')[0].value = '420'; + document.getElementsByClassName('gm-gps-longitude')[0].value = '666'; + document.getElementsByClassName('gm-gps-accuracy')[0].value = '6969'; + document.getElementsByClassName('gm-gps-bearing')[0].value = '4242'; + document.getElementsByClassName('gm-gps-speed')[0].value = '300000000'; + document.getElementsByClassName('gm-gps-submit')[0].click(); + + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({ + channel: 'gps', messages: [ + 'set altitude 10000', + 'set longitude 180', + 'set latitude 90', + 'set accuracy 200', + 'set bearing 360', + 'set speed 399.99', + 'enable' + ], + }); + }); + + test('nominal value', () => { + document.getElementsByClassName('gm-gps-altitude')[0].value = '420'; + document.getElementsByClassName('gm-gps-latitude')[0].value = '69'; // Nice + document.getElementsByClassName('gm-gps-longitude')[0].value = '3.14'; + document.getElementsByClassName('gm-gps-accuracy')[0].value = '42'; + document.getElementsByClassName('gm-gps-bearing')[0].value = '13'; + document.getElementsByClassName('gm-gps-speed')[0].value = '399'; + document.getElementsByClassName('gm-gps-submit')[0].click(); + + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({ + channel: 'gps', messages: [ + 'set altitude 420', + 'set longitude 3.14', + 'set latitude 69', + 'set accuracy 42', + 'set bearing 13', + 'set speed 399', + 'enable' + ], + }); + }); + }); +}); diff --git a/tests/unit/identifiers.test.js b/tests/unit/identifiers.test.js new file mode 100644 index 0000000..162ffd1 --- /dev/null +++ b/tests/unit/identifiers.test.js @@ -0,0 +1,185 @@ +'use strict'; + +const Identifiers = require('../../src/plugins/Identifiers'); +const Instance = require('../mocks/GenymotionInstance'); + +let identifiers; +let instance; +let plugin; + +describe('Identifiers Plugin', () => { + beforeEach(() => { + instance = new Instance(); + identifiers = new Identifiers(instance, {}); + plugin = document.getElementsByClassName('gm-identifiers-plugin')[0]; + }); + + describe('api', () => { + test('exposes a high level constructor', () => { + expect(typeof Identifiers).toBe('function'); + }); + }); + + describe('UI', () => { + beforeEach(() => { + instance = new Instance(); + new Identifiers(instance, { + IDENTIFIERS_TITLE: 'TEST IDENTIFIERS PLUGIN TITLE', + IDENTIFIERS_UPDATE: 'TEST IDENTIFIERS PLUGIN UPDATE BUTTON', + IDENTIFIERS_GENERATE: 'TEST IDENTIFIERS PLUGIN GENERATE BUTTON' + }); + plugin = document.getElementsByClassName('gm-identifiers-plugin')[0]; + }); + + test('is initialized properly at construct', () => { + // Widget + expect(document.getElementsByClassName('gm-identifiers-plugin')).toHaveLength(1); + // Toolbar button + expect(document.getElementsByClassName('gm-identifiers-button')).toHaveLength(1); + }); + + test('has translations', () => { + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST IDENTIFIERS PLUGIN TITLE')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST IDENTIFIERS PLUGIN UPDATE BUTTON')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST IDENTIFIERS PLUGIN GENERATE BUTTON')); + }); + + describe('field validation', () => { + ['android', 'device'].forEach((field) => { + test('button disabled', () => { + const fieldInput = document.getElementsByClassName(`gm-identifier-${field}-input`)[0]; + const button = document.getElementsByClassName('gm-action gm-identifiers-update')[0]; + fieldInput.value = 'jean-michel'; + fieldInput.dispatchEvent(new Event('keyup')); + + expect(fieldInput.classList.contains('gm-error')).toBeTruthy(); + expect(button.disabled).toBeTruthy(); + }); + }); + }); + }); + + describe('incoming events', () => { + test('ANDROID_ID', () => { + ['jean-michel', '123', '0123456789abcdef0', ''].forEach((invalidValue) => { + instance.emit('ANDROID_ID', invalidValue); + identifiers.validateAndroidId(); + expect(identifiers.invalidAndroidId).toBeTruthy(); + }); + + ['0123456789abcdef'].forEach((validValue) => { + instance.emit('ANDROID_ID', validValue); + identifiers.validateAndroidId(); + expect(identifiers.invalidAndroidId).toBeFalsy(); + }); + }); + + test('IMEI', () => { + ['jean-michel', '123', '', '0123456789abcdef'].forEach((invalidValue) => { + instance.emit('IMEI', invalidValue); + identifiers.validateDeviceId(); + expect(identifiers.invalidDeviceId).toBeTruthy(); + }); + + ['0123456789abcd', '0123456789abcde'].forEach((validValue) => { + instance.emit('IMEI', validValue); + identifiers.validateDeviceId(); + expect(identifiers.invalidDeviceId).toBeFalsy(); + }); + }); + + describe('settings', () => { + test('unrelevant topics', () => { + ['unrelevant', 'parameters unrelevant:value', ''].forEach((invalidValue) => { + instance.emit('settings', `${invalidValue}`); + identifiers.validateAndroidId(); + identifiers.validateDeviceId(); + expect(identifiers.invalidAndroidId).toBeTruthy(); + expect(identifiers.invalidDeviceId).toBeTruthy(); + }); + }); + + test('android_id', () => { + ['jean-michel', '123', '0123456789abcdef0', ''].forEach((invalidValue) => { + instance.emit('settings', `parameter android_id:${invalidValue}`); + identifiers.validateAndroidId(); + expect(identifiers.invalidAndroidId).toBeTruthy(); + }); + + ['0123456789abcdef'].forEach((validValue) => { + instance.emit('settings', `parameter android_id:${validValue}`); + identifiers.validateAndroidId(); + expect(identifiers.invalidAndroidId).toBeFalsy(); + }); + }); + + test('device_id', () => { + ['jean-michel', '123', '', '0123456789abcdef'].forEach((invalidValue) => { + instance.emit('settings', `parameter device_id:${invalidValue}`); + identifiers.validateDeviceId(); + expect(identifiers.invalidDeviceId).toBeTruthy(); + }); + + ['0123456789abcd', '0123456789abcde'].forEach((validValue) => { + instance.emit('settings', `parameter device_id:${validValue}`); + identifiers.validateDeviceId(); + expect(identifiers.invalidDeviceId).toBeFalsy(); + }); + }); + }); + }); + + test('outgoing events', () => { + const sendEventSpy = jest.spyOn(instance, 'sendEvent'); + + identifiers.androidInput.value = 'jean-michel'; + identifiers.deviceInput.value = 'jean-michel'; + identifiers.sendDataToInstance(new Event('')); + expect(sendEventSpy).toHaveBeenCalledTimes(0); + + identifiers.androidInput.value = 'jean-michel'; + identifiers.deviceInput.value = '0123456789abcde'; + identifiers.sendDataToInstance(new Event('')); + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({ + channel : 'settings' , messages : [ + 'set parameter device_id:0123456789abcde' + ] + }); + + identifiers.androidInput.value = '0123456789abcdef'; + identifiers.deviceInput.value = 'jean-michel'; + identifiers.sendDataToInstance(new Event('')); + expect(sendEventSpy).toHaveBeenCalledTimes(2); + expect(instance.outgoingMessages[1]).toEqual({ + channel : 'framework' , messages : [ + 'set parameter android_id:0123456789abcdef' + ] + }); + + identifiers.androidInput.value = '0123456789abcdef'; + identifiers.deviceInput.value = '0123456789abcde'; + identifiers.sendDataToInstance(new Event('')); + expect(sendEventSpy).toHaveBeenCalledTimes(4); + expect(instance.outgoingMessages[2]).toEqual({ + channel : 'framework' , messages : [ + 'set parameter android_id:0123456789abcdef' + ] + }); + expect(instance.outgoingMessages[3]).toEqual({ + channel : 'settings' , messages : [ + 'set parameter device_id:0123456789abcde' + ] + }); + + identifiers.androidInput.value = '1234567891234@é%'; + identifiers.deviceInput.value = '0123456789abcde'; + identifiers.sendDataToInstance(new Event('')); + expect(sendEventSpy).toHaveBeenCalledTimes(5); + expect(instance.outgoingMessages[4]).toEqual({ + channel : 'settings' , messages : [ + 'set parameter device_id:0123456789abcde' + ] + }); + }); +}); diff --git a/tests/unit/iothrottling.test.js b/tests/unit/iothrottling.test.js new file mode 100644 index 0000000..20bd99c --- /dev/null +++ b/tests/unit/iothrottling.test.js @@ -0,0 +1,155 @@ +'use strict'; + +const IOThrottling = require('../../src/plugins/IOThrottling'); +const IOThrottlingProfiles = require('../../src/plugins/util/iothrottling-profiles'); +const Instance = require('../mocks/GenymotionInstance'); + +let diskio; +let instance; +let plugin; + +describe('IOThrottling Plugin', () => { + beforeEach(() => { + instance = new Instance(); + diskio = new IOThrottling(instance, {}); + plugin = document.getElementsByClassName('gm-iothrottling-plugin')[0]; + }); + + describe('api', () => { + test('exposes a high level constructor', () => { + expect(typeof IOThrottling).toBe('function'); + }); + }); + + describe('UI', () => { + beforeEach(() => { + instance = new Instance(); + new IOThrottling(instance, { + IOTHROTTLING_TITLE: 'TEST IOTHROTTLING PLUGIN TITLE', + IOTHROTTLING_PROFILE: 'TEST IOTHROTTLING PLUGIN PROFILE', + IOTHROTTLING_PROFILE_NONE: 'TEST IOTHROTTLING PLUGIN PROFILE NONE', + IOTHROTTLING_READ_BYTERATE: 'TEST IOTHROTTLING PLUGIN READ BYTERATE', + IOTHROTTLING_READ_BYTERATE_EXAMPLE: 'TEST IOTHROTTLING PLUGIN READ BYTERATE EXAMPLE', + IOTHROTTLING_BYTERATE_UNIT: 'TEST IOTHROTTLING PLUGIN BYTERATE UNIT', + IOTHROTTLING_UPDATE: 'TEST IOTHROTTLING PLUGIN UPDATE BUTTON', + IOTHROTTLING_CLEAR_CACHE: 'TEST IOTHROTTLING PLUGIN CLEAR CACHE BUTTON' + }); + plugin = document.getElementsByClassName('gm-iothrottling-plugin')[0]; + }); + + test('is initialized properly at construct', () => { + // Widget + expect(document.getElementsByClassName('gm-iothrottling-plugin')).toHaveLength(1); + // Toolbar button + expect(document.getElementsByClassName('gm-iothrottling-button')).toHaveLength(1); + }); + + test('has translations', () => { + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST IOTHROTTLING PLUGIN TITLE')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST IOTHROTTLING PLUGIN PROFILE')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST IOTHROTTLING PLUGIN PROFILE NONE')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST IOTHROTTLING PLUGIN READ BYTERATE')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST IOTHROTTLING PLUGIN READ BYTERATE EXAMPLE')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST IOTHROTTLING PLUGIN BYTERATE UNIT')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST IOTHROTTLING PLUGIN UPDATE BUTTON')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST IOTHROTTLING PLUGIN CLEAR CACHE BUTTON')); + }); + }); + + describe('incoming events', () => { + test('BLK', () => { + ['jean-michel', '-123', ''].forEach((invalidValue) => { + instance.emit('BLK', invalidValue); + expect(diskio.select.value).toBe('None'); + }); + + [69, 420].forEach((customValue) => { + instance.emit('BLK', customValue * 1024); + expect(diskio.select.value).toBe('Custom'); + expect(Number(diskio.readByteRate.value)).toBe(customValue); + }); + + IOThrottlingProfiles.forEach((profile) => { + if (!profile.readByteRate) { + return; + } + + instance.emit('BLK', profile.readByteRate * 1024); + expect(diskio.select.value).toBe(profile.name); + expect(Number(diskio.readByteRate.value)).toBe(profile.readByteRate); + }); + }); + + test('diskio', () => { + ['jean-michel', 'readbyterate -123', '', 'readbyterate invalid'].forEach((invalidValue) => { + instance.emit('diskio', invalidValue); + expect(diskio.select.value).toBe('None'); + }); + + [69, 420].forEach((customValue) => { + instance.emit('diskio', `readbyterate ${customValue * 1024 * 1024}`); + expect(diskio.select.value).toBe('Custom'); + expect(Number(diskio.readByteRate.value)).toBe(customValue); + }); + + IOThrottlingProfiles.forEach((profile) => { + if (!profile.readByteRate) { + return; + } + + instance.emit('diskio', `readbyterate ${profile.readByteRate * 1024 * 1024}`); + expect(diskio.select.value).toBe(profile.name); + expect(Number(diskio.readByteRate.value)).toBe(profile.readByteRate); + }); + }); + }); + + describe('outgoing events', () => { + test('readbyterate', () => { + const sendEventSpy = jest.spyOn(instance, 'sendEvent'); + + IOThrottlingProfiles.forEach((profile) => { + if (!profile.readByteRate) { + return; + } + + sendEventSpy.mockClear(); + instance.outgoingMessages = []; + diskio.select.value = profile.name; + diskio.select.dispatchEvent(new Event('change')); + diskio.submitBtn.click(); + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({ + channel: 'diskio', messages: [ + 'set readbyterate ' + profile.readByteRate * 1024 * 1024, + 'clearcache' + ] + }); + }); + + sendEventSpy.mockClear(); + instance.outgoingMessages = []; + diskio.select.value = 'Custom'; + diskio.select.dispatchEvent(new Event('change')); + diskio.readByteRate.value = 69; // Nice + diskio.submitBtn.click(); + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({ + channel: 'diskio', messages: [ + 'set readbyterate ' + 69 * 1024 * 1024, + 'clearcache' + ] + }); + }); + + test('readbyterate', () => { + const sendEventSpy = jest.spyOn(instance, 'sendEvent'); + + diskio.clearCacheBtn.click(); + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({ + channel: 'diskio', messages: ['clearcache'] + }); + }); + }); +}); diff --git a/tests/unit/network.test.js b/tests/unit/network.test.js new file mode 100644 index 0000000..f0dc94c --- /dev/null +++ b/tests/unit/network.test.js @@ -0,0 +1,236 @@ +'use strict'; + +const Network = require('../../src/plugins/Network'); +const NetworkProfiles = require('../../src/plugins/util/network-profiles'); +const Instance = require('../mocks/GenymotionInstance'); + +let network; +let instance; +let plugin; + +describe('Network Plugin', () => { + beforeEach(() => { + instance = new Instance(); + network = new Network(instance, {}, true); + plugin = document.getElementsByClassName('gm-network-plugin')[0]; + }); + + describe('api', () => { + test('exposes a high level constructor', () => { + expect(typeof Network).toBe('function'); + }); + }); + + describe('UI', () => { + beforeEach(() => { + instance = new Instance(); + new Network(instance, { + NETWORK_TITLE: 'TEST NETWORK PLUGIN TITLE', + NETWORK_DELECT_PROFILE: 'TEST NETWORK PLUGIN DETECT PROFILE', + NETWORK_OPERATOR: 'TEST NETWORK PLUGIN NETWORK OPERATOR', + NETWORK_SIM_OPERATOR: 'TEST NETWORK PLUGIN SIM OPERATOR', + NETWORK_UPDATE: 'TEST NETWORK PLUGIN UPDATE' + }, true); + plugin = document.getElementsByClassName('gm-network-plugin')[0]; + }); + + test('is initialized properly at construct', () => { + // Widget + expect(document.getElementsByClassName('gm-network-plugin')).toHaveLength(1); + // Toolbar button + expect(document.getElementsByClassName('gm-network-button')).toHaveLength(1); + }); + + test('has translations', () => { + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST NETWORK PLUGIN TITLE')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST NETWORK PLUGIN DETECT PROFILE')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST NETWORK PLUGIN NETWORK OPERATOR')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST NETWORK PLUGIN SIM OPERATOR')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST NETWORK PLUGIN UPDATE')); + }); + }); + + describe('incoming events', () => { + test('NETWORK', () => { + const loadDetails = jest.spyOn(network, 'loadDetails'); + + ['jean-michel', '-123', '', '9'].forEach((invalidValue) => { + instance.emit('NETWORK', invalidValue); + expect(loadDetails).not.toHaveBeenCalled(); + }); + + NetworkProfiles.forEach((profile) => { + instance.emit('NETWORK', profile.id); + expect(loadDetails).toHaveBeenCalledWith(NetworkProfiles[NetworkProfiles.length - 1 - profile.id]); + loadDetails.mockReset(); + }); + }); + + test('network_profile', () => { + const loadDetails = jest.spyOn(network, 'loadDetails'); + + ['jean-michel', 'state wifi -123', '', 'state wifi missing:additional:values'].forEach((invalidValue) => { + instance.emit('network_profile', invalidValue); + expect(loadDetails).not.toHaveBeenCalled(); + }); + + NetworkProfiles.forEach((profile) => { + let message = 'state wifi '; + message += `up_rate:enabled:${profile.upSpeed.value} `; + message += `down_rate:enabled:${profile.downSpeed.value} `; + message += `up_delay:enabled:${profile.upDelay.value} `; + message += `down_delay:enabled:${profile.downDelay.value} `; + message += `up_pkt_loss:enabled:${profile.upPacketLoss.value} `; + message += `down_pkt_loss:enabled:${profile.downPacketLoss.value} `; + message += `dns_delay:enabled:${profile.dnsDelay.value}`; + instance.emit('network_profile', message); + expect(loadDetails).toHaveBeenCalledWith(NetworkProfiles[NetworkProfiles.length - 1 - profile.id]); + loadDetails.mockReset(); + }); + + let message = 'state wifi '; + message += `up_rate:enabled:${NetworkProfiles[0].upSpeed.value + 1} `; // Unexpected value + message += `down_rate:enabled:${NetworkProfiles[0].downSpeed.value} `; + message += `up_delay:enabled:${NetworkProfiles[0].upDelay.value} `; + message += `down_delay:enabled:${NetworkProfiles[0].downDelay.value} `; + message += `up_pkt_loss:enabled:${NetworkProfiles[0].upPacketLoss.value} `; + message += `down_pkt_loss:enabled:${NetworkProfiles[0].downPacketLoss.value} `; + message += `dns_delay:enabled:${NetworkProfiles[0].dnsDelay.value}`; + instance.emit('network_profile', message); + expect(loadDetails).not.toHaveBeenCalled(); + loadDetails.mockReset(); + + message = 'state wifi '; + message += `up_rate:disabled:${NetworkProfiles[0].upSpeed.value} `; // Disabled value + message += `down_rate:enabled:${NetworkProfiles[0].downSpeed.value} `; + message += `up_delay:enabled:${NetworkProfiles[0].upDelay.value} `; + message += `down_delay:enabled:${NetworkProfiles[0].downDelay.value} `; + message += `up_pkt_loss:enabled:${NetworkProfiles[0].upPacketLoss.value} `; + message += `down_pkt_loss:enabled:${NetworkProfiles[0].downPacketLoss.value} `; + message += `dns_delay:enabled:${NetworkProfiles[0].dnsDelay.value}`; + instance.emit('network_profile', message); + expect(loadDetails).not.toHaveBeenCalled(); + loadDetails.mockReset(); + }); + + describe('baseband', () => { + describe('network', () => { + test('operator', () => { + ['jean-michel', '-123', ''].forEach((value) => { + instance.emit('baseband', `network operator ${value}`); + expect(network.networkOperatorMMC.value).toBe(value); + }); + }); + + test('operator_name', () => { + ['jean-michel', '-123', ''].forEach((value) => { + instance.emit('baseband', `network operator_name ${value}`); + expect(network.networkOperatorName.value).toBe(value); + }); + }); + }); + + describe('sim', () => { + test('operator', () => { + ['jean-michel', '-123', ''].forEach((value) => { + instance.emit('baseband', `sim operator ${value}`); + expect(network.simOperatorMMC.value).toBe(value); + }); + }); + + test('operator_name', () => { + ['jean-michel', '-123', ''].forEach((value) => { + instance.emit('baseband', `sim operator_name ${value}`); + expect(network.simOperatorName.value).toBe(value); + }); + }); + + test('imsi_id', () => { + ['jean-michel', '-123', ''].forEach((value) => { + instance.emit('baseband', `sim imsi_id ${value}`); + expect(network.simMSIN.value).toBe(value); + }); + }); + + test('phone_number', () => { + ['jean-michel', '-123', ''].forEach((value) => { + instance.emit('baseband', `sim phone_number ${value}`); + expect(network.simOperatorPhoneNumber.value).toBe(value); + }); + }); + }); + }); + }); + + describe('outgoing events', () => { + test('wifi', () => { + instance = new Instance(); + network = new Network(instance, {}, false); + const sendEventSpy = jest.spyOn(instance, 'sendEvent'); + + NetworkProfiles.forEach((profile) => { + sendEventSpy.mockClear(); + instance.outgoingMessages = []; + const messages = []; + + if (profile.id === 0) { + messages.push('disable wifi all'); + } else { + messages.push('enable wifi all'); + messages.push(`set wifi up_rate ${profile.upSpeed.value}`); + messages.push(`set wifi down_rate ${profile.downSpeed.value}`); + messages.push(`set wifi up_delay ${profile.upDelay.value}`); + messages.push(`set wifi down_delay ${profile.downDelay.value}`); + messages.push(`set wifi up_pkt_loss ${profile.upPacketLoss.value}`); + messages.push(`set wifi down_pkt_loss ${profile.downPacketLoss.value}`); + messages.push(`set wifi dns_delay ${profile.dnsDelay.value}`); + } + + network.setActive(profile.id); + network.submitBtn.click(); + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({channel: 'network_profile', messages: messages}); + }); + + sendEventSpy.mockClear(); + network.select.value = 'Select a profile'; + network.submitBtn.click(); + expect(sendEventSpy).toHaveBeenCalledTimes(0); + }); + + test('baseband', () => { + instance = new Instance(); + network = new Network(instance, {}, true); + const sendEventSpy = jest.spyOn(instance, 'sendEvent'); + + network.select.value = 'Select a profile'; + network.submitBtn.click(); + expect(sendEventSpy).toHaveBeenCalledTimes(0); + + network.networkOperatorMMC.value = '123456'; + network.networkOperatorName.value = 'value'; + network.simOperatorMMC.value = '123456'; + network.submitBtn.click(); + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({channel: 'baseband', messages: [ + 'network operator 123456', + 'network operator_name value', + 'sim operator 123456', + ]}); + + network.simOperatorName.value = 'value'; + network.simMSIN.value = '0123456789'; + network.simOperatorPhoneNumber.value = '0011223344'; + network.submitBtn.click(); + expect(sendEventSpy).toHaveBeenCalledTimes(2); + expect(instance.outgoingMessages[1]).toEqual({channel: 'baseband', messages: [ + 'network operator 123456', + 'network operator_name value', + 'sim operator 123456', + 'sim operator_name value', + 'sim imsi_id 0123456789', + 'sim phone_number 0011223344' + ]}); + }); + }); +}); diff --git a/tests/unit/phone.test.js b/tests/unit/phone.test.js new file mode 100644 index 0000000..fdce600 --- /dev/null +++ b/tests/unit/phone.test.js @@ -0,0 +1,92 @@ +'use strict'; + +const Phone = require('../../src/plugins/Phone'); +const Instance = require('../mocks/GenymotionInstance'); + +let phone; +let instance; +let plugin; + +describe('Phone Plugin', () => { + beforeEach(() => { + instance = new Instance(); + phone = new Phone(instance, {}); + plugin = document.getElementsByClassName('gm-phone-plugin')[0]; + }); + + describe('api', () => { + test('exposes a high level constructor', () => { + expect(typeof Phone).toBe('function'); + }); + }); + + describe('UI', () => { + beforeEach(() => { + instance = new Instance(); + new Phone(instance, { + PHONE_TITLE: 'TEST PHONE PLUGIN TITLE', + PHONE_CALL_PLACEHOLDER: 'TEST PHONE PLUGIN CALL PLACEHOLDER', + PHONE_CALL: 'TEST PHONE PLUGIN CALL', + PHONE_INCOMING: 'TEST PHONE PLUGIN INCOMING', + PHONE_MESSAGE_PLACEHOLDER: 'TEST PHONE PLUGIN MESSAGE PLACEHOLDER', + PHONE_MESSAGE: 'TEST PHONE PLUGIN MESSAGE', + PHONE_MESSAGE_VALUE: 'TEST PHONE PLUGIN MESSAGE_VALUE' + }); + plugin = document.getElementsByClassName('gm-phone-plugin')[0]; + }); + + test('is initialized properly at construct', () => { + // Widget + expect(document.getElementsByClassName('gm-phone-plugin')).toHaveLength(1); + // Toolbar button + expect(document.getElementsByClassName('gm-phone-button')).toHaveLength(1); + }); + + test('has translations', () => { + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST PHONE PLUGIN TITLE')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST PHONE PLUGIN CALL PLACEHOLDER')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST PHONE PLUGIN CALL')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST PHONE PLUGIN INCOMING')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST PHONE PLUGIN MESSAGE PLACEHOLDER')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST PHONE PLUGIN MESSAGE')); + expect(plugin.innerHTML).toEqual(expect.stringContaining('TEST PHONE PLUGIN MESSAGE_VALUE')); + }); + }); + + describe('outgoing events', () => { + test('gsm call', () => { + const sendEventSpy = jest.spyOn(instance, 'sendEvent'); + + ['jean-michel', '-666', ''].forEach((invalidValue) => { + phone.phoneInput.value = invalidValue; + phone.sendPhoneCallToInstance(); + expect(sendEventSpy).toHaveBeenCalledTimes(0); + }); + + phone.phoneInput.value = '0123456789'; + phone.sendPhoneCallToInstance(); + expect(sendEventSpy).toHaveBeenCalledTimes(1); + + expect(instance.outgoingMessages[0]).toEqual({channel: 'baseband', messages: [ + 'gsm call 0123456789' + ]}); + }); + + test('sms send', () => { + const sendEventSpy = jest.spyOn(instance, 'sendEvent'); + phone.phoneInput.value = '0123456789'; + + phone.textInput.value = ''; + phone.sendSMSToInstance(); + expect(sendEventSpy).toHaveBeenCalledTimes(0); + + phone.textInput.value = 'Hello world'; + phone.sendSMSToInstance(); + expect(sendEventSpy).toHaveBeenCalledTimes(1); + + expect(instance.outgoingMessages[0]).toEqual({channel: 'baseband', messages: [ + 'sms send 0123456789 Hello world' + ]}); + }); + }); +}); diff --git a/tests/unit/streambitrate.test.js b/tests/unit/streambitrate.test.js new file mode 100644 index 0000000..aaff9f3 --- /dev/null +++ b/tests/unit/streambitrate.test.js @@ -0,0 +1,62 @@ +'use strict'; + +const StreamBitrate = require('../../src/plugins/StreamBitrate'); +const Instance = require('../mocks/GenymotionInstance'); + +let chooser; +let instance; + +describe.only('StreamBitrate Plugin', () => { + beforeEach(() => { + instance = new Instance(); + chooser = new StreamBitrate(instance, {}); + }); + + describe('api', () => { + test('exposes a high level constructor', () => { + expect(typeof StreamBitrate).toBe('function'); + }); + }); + + describe('UI', () => { + beforeEach(() => { + instance = new Instance(); + new StreamBitrate(instance, { + STREAMRATE_TITLE: 'TEST QUALITY PLUGIN TITLE' + }); + }); + + test('is initialized properly at construct', () => { + // Toolbar button + expect(document.getElementsByClassName('gm-streamrate-button')).toHaveLength(1); + }); + }); + + describe('outgoing events', () => { + test('hq', () => { + const sendEventSpy = jest.spyOn(instance, 'sendEvent'); + + chooser.highQuality = false; + chooser.chooser.click(); + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({type: 'BITRATE', videoBitrate: 5000, audioBitrate: 192000}); + + chooser.chooser.click(); + expect(sendEventSpy).toHaveBeenCalledTimes(2); + expect(instance.outgoingMessages[1]).toEqual({type: 'BITRATE', videoBitrate: 0, audioBitrate: 0}); + }); + + test('default', () => { + const sendEventSpy = jest.spyOn(instance, 'sendEvent'); + + chooser.highQuality = true; + chooser.chooser.click(); + expect(sendEventSpy).toHaveBeenCalledTimes(1); + expect(instance.outgoingMessages[0]).toEqual({type: 'BITRATE', videoBitrate: 0, audioBitrate: 0}); + + chooser.chooser.click(); + expect(sendEventSpy).toHaveBeenCalledTimes(2); + expect(instance.outgoingMessages[1]).toEqual({type: 'BITRATE', videoBitrate: 5000, audioBitrate: 192000}); + }); + }); +}); diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..df73f39 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,9535 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.10.4.tgz#168da1a36e90da68ae8d49c0f1b48c7c6249213a" + integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/compat-data@^7.12.1", "@babel/compat-data@^7.12.5": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.12.5.tgz#f56db0c4bb1bbbf221b4e81345aab4141e7cb0e9" + integrity sha512-DTsS7cxrsH3by8nqQSpFSyjSfSYl57D6Cf4q8dW3LK83tBKBDCkfcay1nYkXq1nIHXnpX8WMMb/O25HOy3h1zg== + +"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.7.5": + version "7.12.3" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.12.3.tgz#1b436884e1e3bff6fb1328dc02b208759de92ad8" + integrity sha512-0qXcZYKZp3/6N2jKYVxZv0aNCsxTSVCiK72DTiTYZAu7sjg73W0/aynWjMbiGd87EQL4WyA8reiJVh92AVla9g== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.12.1" + "@babel/helper-module-transforms" "^7.12.1" + "@babel/helpers" "^7.12.1" + "@babel/parser" "^7.12.3" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.12.1" + "@babel/types" "^7.12.1" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.2" + lodash "^4.17.19" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/generator@^7.12.1", "@babel/generator@^7.12.5": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.5.tgz#a2c50de5c8b6d708ab95be5e6053936c1884a4de" + integrity sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A== + dependencies: + "@babel/types" "^7.12.5" + jsesc "^2.5.1" + source-map "^0.5.0" + +"@babel/helper-annotate-as-pure@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz#5bf0d495a3f757ac3bda48b5bf3b3ba309c72ba3" + integrity sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA== + dependencies: + "@babel/types" "^7.10.4" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz#bb0b75f31bf98cbf9ff143c1ae578b87274ae1a3" + integrity sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.10.4" + "@babel/types" "^7.10.4" + +"@babel/helper-compilation-targets@^7.12.1": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.12.5.tgz#cb470c76198db6a24e9dbc8987275631e5d29831" + integrity sha512-+qH6NrscMolUlzOYngSBMIOQpKUGPPsc61Bu5W10mg84LxZ7cmvnBHzARKbDoFxVvqqAbj6Tg6N7bSrWSPXMyw== + dependencies: + "@babel/compat-data" "^7.12.5" + "@babel/helper-validator-option" "^7.12.1" + browserslist "^4.14.5" + semver "^5.5.0" + +"@babel/helper-create-class-features-plugin@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.12.1.tgz#3c45998f431edd4a9214c5f1d3ad1448a6137f6e" + integrity sha512-hkL++rWeta/OVOBTRJc9a5Azh5mt5WgZUGAKMD8JM141YsE08K//bp1unBBieO6rUKkIPyUE0USQ30jAy3Sk1w== + dependencies: + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-member-expression-to-functions" "^7.12.1" + "@babel/helper-optimise-call-expression" "^7.10.4" + "@babel/helper-replace-supers" "^7.12.1" + "@babel/helper-split-export-declaration" "^7.10.4" + +"@babel/helper-create-regexp-features-plugin@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.1.tgz#18b1302d4677f9dc4740fe8c9ed96680e29d37e8" + integrity sha512-rsZ4LGvFTZnzdNZR5HZdmJVuXK8834R5QkF3WvcnBhrlVtF0HSIUC6zbreL9MgjTywhKokn8RIYRiq99+DLAxA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-regex" "^7.10.4" + regexpu-core "^4.7.1" + +"@babel/helper-define-map@^7.10.4": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz#b53c10db78a640800152692b13393147acb9bb30" + integrity sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ== + dependencies: + "@babel/helper-function-name" "^7.10.4" + "@babel/types" "^7.10.5" + lodash "^4.17.19" + +"@babel/helper-explode-assignable-expression@^7.10.4": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.12.1.tgz#8006a466695c4ad86a2a5f2fb15b5f2c31ad5633" + integrity sha512-dmUwH8XmlrUpVqgtZ737tK88v07l840z9j3OEhCLwKTkjlvKpfqXVIZ0wpK3aeOxspwGrf/5AP5qLx4rO3w5rA== + dependencies: + "@babel/types" "^7.12.1" + +"@babel/helper-function-name@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz#d2d3b20c59ad8c47112fa7d2a94bc09d5ef82f1a" + integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ== + dependencies: + "@babel/helper-get-function-arity" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/types" "^7.10.4" + +"@babel/helper-get-function-arity@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz#98c1cbea0e2332f33f9a4661b8ce1505b2c19ba2" + integrity sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A== + dependencies: + "@babel/types" "^7.10.4" + +"@babel/helper-hoist-variables@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz#d49b001d1d5a68ca5e6604dda01a6297f7c9381e" + integrity sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA== + dependencies: + "@babel/types" "^7.10.4" + +"@babel/helper-member-expression-to-functions@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.1.tgz#fba0f2fcff3fba00e6ecb664bb5e6e26e2d6165c" + integrity sha512-k0CIe3tXUKTRSoEx1LQEPFU9vRQfqHtl+kf8eNnDqb4AUJEy5pz6aIiog+YWtVm2jpggjS1laH68bPsR+KWWPQ== + dependencies: + "@babel/types" "^7.12.1" + +"@babel/helper-module-imports@^7.12.1": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz#1bfc0229f794988f76ed0a4d4e90860850b54dfb" + integrity sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA== + dependencies: + "@babel/types" "^7.12.5" + +"@babel/helper-module-transforms@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz#7954fec71f5b32c48e4b303b437c34453fd7247c" + integrity sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w== + dependencies: + "@babel/helper-module-imports" "^7.12.1" + "@babel/helper-replace-supers" "^7.12.1" + "@babel/helper-simple-access" "^7.12.1" + "@babel/helper-split-export-declaration" "^7.11.0" + "@babel/helper-validator-identifier" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.12.1" + "@babel/types" "^7.12.1" + lodash "^4.17.19" + +"@babel/helper-optimise-call-expression@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz#50dc96413d594f995a77905905b05893cd779673" + integrity sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg== + dependencies: + "@babel/types" "^7.10.4" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" + integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== + +"@babel/helper-regex@^7.10.4": + version "7.10.5" + resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.10.5.tgz#32dfbb79899073c415557053a19bd055aae50ae0" + integrity sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg== + dependencies: + lodash "^4.17.19" + +"@babel/helper-remap-async-to-generator@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.12.1.tgz#8c4dbbf916314f6047dc05e6a2217074238347fd" + integrity sha512-9d0KQCRM8clMPcDwo8SevNs+/9a8yWVVmaE80FGJcEP8N1qToREmWEGnBn8BUlJhYRFz6fqxeRL1sl5Ogsed7A== + dependencies: + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-wrap-function" "^7.10.4" + "@babel/types" "^7.12.1" + +"@babel/helper-replace-supers@^7.12.1": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz#f009a17543bbbbce16b06206ae73b63d3fca68d9" + integrity sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.12.1" + "@babel/helper-optimise-call-expression" "^7.10.4" + "@babel/traverse" "^7.12.5" + "@babel/types" "^7.12.5" + +"@babel/helper-simple-access@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz#32427e5aa61547d38eb1e6eaf5fd1426fdad9136" + integrity sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA== + dependencies: + "@babel/types" "^7.12.1" + +"@babel/helper-skip-transparent-expression-wrappers@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz#462dc63a7e435ade8468385c63d2b84cce4b3cbf" + integrity sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA== + dependencies: + "@babel/types" "^7.12.1" + +"@babel/helper-split-export-declaration@^7.10.4", "@babel/helper-split-export-declaration@^7.11.0": + version "7.11.0" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz#f8a491244acf6a676158ac42072911ba83ad099f" + integrity sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg== + dependencies: + "@babel/types" "^7.11.0" + +"@babel/helper-validator-identifier@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" + integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== + +"@babel/helper-validator-option@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.1.tgz#175567380c3e77d60ff98a54bb015fe78f2178d9" + integrity sha512-YpJabsXlJVWP0USHjnC/AQDTLlZERbON577YUVO/wLpqyj6HAtVYnWaQaN0iUN+1/tWn3c+uKKXjRut5115Y2A== + +"@babel/helper-wrap-function@^7.10.4": + version "7.12.3" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.12.3.tgz#3332339fc4d1fbbf1c27d7958c27d34708e990d9" + integrity sha512-Cvb8IuJDln3rs6tzjW3Y8UeelAOdnpB8xtQ4sme2MSZ9wOxrbThporC0y/EtE16VAtoyEfLM404Xr1e0OOp+ow== + dependencies: + "@babel/helper-function-name" "^7.10.4" + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.10.4" + "@babel/types" "^7.10.4" + +"@babel/helpers@^7.12.1": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.12.5.tgz#1a1ba4a768d9b58310eda516c449913fe647116e" + integrity sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA== + dependencies: + "@babel/template" "^7.10.4" + "@babel/traverse" "^7.12.5" + "@babel/types" "^7.12.5" + +"@babel/highlight@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143" + integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA== + dependencies: + "@babel/helper-validator-identifier" "^7.10.4" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.10.4", "@babel/parser@^7.12.3", "@babel/parser@^7.12.5", "@babel/parser@^7.7.0": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.5.tgz#b4af32ddd473c0bfa643bd7ff0728b8e71b81ea0" + integrity sha512-FVM6RZQ0mn2KCf1VUED7KepYeUWoVShczewOCfm3nzoBybaih51h+sYVVGthW9M6lPByEPTQf+xm27PBdlpwmQ== + +"@babel/plugin-proposal-async-generator-functions@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.1.tgz#dc6c1170e27d8aca99ff65f4925bd06b1c90550e" + integrity sha512-d+/o30tJxFxrA1lhzJqiUcEJdI6jKlNregCv5bASeGf2Q4MXmnwH7viDo7nhx1/ohf09oaH8j1GVYG/e3Yqk6A== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-remap-async-to-generator" "^7.12.1" + "@babel/plugin-syntax-async-generators" "^7.8.0" + +"@babel/plugin-proposal-class-properties@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.12.1.tgz#a082ff541f2a29a4821065b8add9346c0c16e5de" + integrity sha512-cKp3dlQsFsEs5CWKnN7BnSHOd0EOW8EKpEjkoz1pO2E5KzIDNV9Ros1b0CnmbVgAGXJubOYVBOGCT1OmJwOI7w== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.12.1" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-proposal-dynamic-import@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.12.1.tgz#43eb5c2a3487ecd98c5c8ea8b5fdb69a2749b2dc" + integrity sha512-a4rhUSZFuq5W8/OO8H7BL5zspjnc1FLd9hlOxIK/f7qG4a0qsqk8uvF/ywgBA8/OmjsapjpvaEOYItfGG1qIvQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" + +"@babel/plugin-proposal-export-namespace-from@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.1.tgz#8b9b8f376b2d88f5dd774e4d24a5cc2e3679b6d4" + integrity sha512-6CThGf0irEkzujYS5LQcjBx8j/4aQGiVv7J9+2f7pGfxqyKh3WnmVJYW3hdrQjyksErMGBPQrCnHfOtna+WLbw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-proposal-json-strings@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.12.1.tgz#d45423b517714eedd5621a9dfdc03fa9f4eb241c" + integrity sha512-GoLDUi6U9ZLzlSda2Df++VSqDJg3CG+dR0+iWsv6XRw1rEq+zwt4DirM9yrxW6XWaTpmai1cWJLMfM8qQJf+yw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-json-strings" "^7.8.0" + +"@babel/plugin-proposal-logical-assignment-operators@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.12.1.tgz#f2c490d36e1b3c9659241034a5d2cd50263a2751" + integrity sha512-k8ZmVv0JU+4gcUGeCDZOGd0lCIamU/sMtIiX3UWnUc5yzgq6YUGyEolNYD+MLYKfSzgECPcqetVcJP9Afe/aCA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.12.1.tgz#3ed4fff31c015e7f3f1467f190dbe545cd7b046c" + integrity sha512-nZY0ESiaQDI1y96+jk6VxMOaL4LPo/QDHBqL+SF3/vl6dHkTwHlOI8L4ZwuRBHgakRBw5zsVylel7QPbbGuYgg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + +"@babel/plugin-proposal-numeric-separator@^7.12.1": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.5.tgz#b1ce757156d40ed79d59d467cb2b154a5c4149ba" + integrity sha512-UiAnkKuOrCyjZ3sYNHlRlfuZJbBHknMQ9VMwVeX97Ofwx7RpD6gS2HfqTCh8KNUQgcOm8IKt103oR4KIjh7Q8g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-proposal-object-rest-spread@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz#def9bd03cea0f9b72283dac0ec22d289c7691069" + integrity sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-transform-parameters" "^7.12.1" + +"@babel/plugin-proposal-optional-catch-binding@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.12.1.tgz#ccc2421af64d3aae50b558a71cede929a5ab2942" + integrity sha512-hFvIjgprh9mMw5v42sJWLI1lzU5L2sznP805zeT6rySVRA0Y18StRhDqhSxlap0oVgItRsB6WSROp4YnJTJz0g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + +"@babel/plugin-proposal-optional-chaining@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.1.tgz#cce122203fc8a32794296fc377c6dedaf4363797" + integrity sha512-c2uRpY6WzaVDzynVY9liyykS+kVU+WRZPMPYpkelXH8KBt1oXoI89kPbZKKG/jDT5UK92FTW2fZkZaJhdiBabw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + +"@babel/plugin-proposal-private-methods@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.12.1.tgz#86814f6e7a21374c980c10d38b4493e703f4a389" + integrity sha512-mwZ1phvH7/NHK6Kf8LP7MYDogGV+DKB1mryFOEwx5EBNQrosvIczzZFTUmWaeujd5xT6G1ELYWUz3CutMhjE1w== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.12.1" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-proposal-unicode-property-regex@^7.12.1", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.1.tgz#2a183958d417765b9eae334f47758e5d6a82e072" + integrity sha512-MYq+l+PvHuw/rKUz1at/vb6nCnQ2gmJBNaM62z0OgH7B2W1D9pvkpYtlti9bGtizNIU1K3zm4bZF9F91efVY0w== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.12.1" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-async-generators@^7.8.0", "@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.1", "@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.1.tgz#bcb297c5366e79bebadef509549cd93b04f19978" + integrity sha512-U40A76x5gTwmESz+qiqssqmeEsKvcSyvtgktrm0uzcARAmM9I1jR221f6Oq+GmHrcD+LvZDag1UTOTe2fL3TeA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-dynamic-import@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.0", "@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0", "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.0", "@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.0", "@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.0", "@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.12.1", "@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.1.tgz#dd6c0b357ac1bb142d98537450a319625d13d2a0" + integrity sha512-i7ooMZFS+a/Om0crxZodrTzNEPJHZrlMVGMTEpFAj6rYY/bKCddB0Dk/YxfPuYXOopuhKk/e1jV6h+WUU9XN3A== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-arrow-functions@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.12.1.tgz#8083ffc86ac8e777fbe24b5967c4b2521f3cb2b3" + integrity sha512-5QB50qyN44fzzz4/qxDPQMBCTHgxg3n0xRBLJUmBlLoU/sFvxVWGZF/ZUfMVDQuJUKXaBhbupxIzIfZ6Fwk/0A== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-async-to-generator@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.12.1.tgz#3849a49cc2a22e9743cbd6b52926d30337229af1" + integrity sha512-SDtqoEcarK1DFlRJ1hHRY5HvJUj5kX4qmtpMAm2QnhOlyuMC4TMdCRgW6WXpv93rZeYNeLP22y8Aq2dbcDRM1A== + dependencies: + "@babel/helper-module-imports" "^7.12.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-remap-async-to-generator" "^7.12.1" + +"@babel/plugin-transform-block-scoped-functions@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.1.tgz#f2a1a365bde2b7112e0a6ded9067fdd7c07905d9" + integrity sha512-5OpxfuYnSgPalRpo8EWGPzIYf0lHBWORCkj5M0oLBwHdlux9Ri36QqGW3/LR13RSVOAoUUMzoPI/jpE4ABcHoA== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-block-scoping@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.1.tgz#f0ee727874b42a208a48a586b84c3d222c2bbef1" + integrity sha512-zJyAC9sZdE60r1nVQHblcfCj29Dh2Y0DOvlMkcqSo0ckqjiCwNiUezUKw+RjOCwGfpLRwnAeQ2XlLpsnGkvv9w== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-classes@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.12.1.tgz#65e650fcaddd3d88ddce67c0f834a3d436a32db6" + integrity sha512-/74xkA7bVdzQTBeSUhLLJgYIcxw/dpEpCdRDiHgPJ3Mv6uC11UhjpOhl72CgqbBCmt1qtssCyB2xnJm1+PFjog== + dependencies: + "@babel/helper-annotate-as-pure" "^7.10.4" + "@babel/helper-define-map" "^7.10.4" + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-optimise-call-expression" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-replace-supers" "^7.12.1" + "@babel/helper-split-export-declaration" "^7.10.4" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.12.1.tgz#d68cf6c9b7f838a8a4144badbe97541ea0904852" + integrity sha512-vVUOYpPWB7BkgUWPo4C44mUQHpTZXakEqFjbv8rQMg7TC6S6ZhGZ3otQcRH6u7+adSlE5i0sp63eMC/XGffrzg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-destructuring@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.12.1.tgz#b9a570fe0d0a8d460116413cb4f97e8e08b2f847" + integrity sha512-fRMYFKuzi/rSiYb2uRLiUENJOKq4Gnl+6qOv5f8z0TZXg3llUwUhsNNwrwaT/6dUhJTzNpBr+CUvEWBtfNY1cw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-dotall-regex@^7.12.1", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.1.tgz#a1d16c14862817b6409c0a678d6f9373ca9cd975" + integrity sha512-B2pXeRKoLszfEW7J4Hg9LoFaWEbr/kzo3teWHmtFCszjRNa/b40f9mfeqZsIDLLt/FjwQ6pz/Gdlwy85xNckBA== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.12.1" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-duplicate-keys@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.1.tgz#745661baba295ac06e686822797a69fbaa2ca228" + integrity sha512-iRght0T0HztAb/CazveUpUQrZY+aGKKaWXMJ4uf9YJtqxSUe09j3wteztCUDRHs+SRAL7yMuFqUsLoAKKzgXjw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-exponentiation-operator@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.1.tgz#b0f2ed356ba1be1428ecaf128ff8a24f02830ae0" + integrity sha512-7tqwy2bv48q+c1EHbXK0Zx3KXd2RVQp6OC7PbwFNt/dPTAV3Lu5sWtWuAj8owr5wqtWnqHfl2/mJlUmqkChKug== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-for-of@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.12.1.tgz#07640f28867ed16f9511c99c888291f560921cfa" + integrity sha512-Zaeq10naAsuHo7heQvyV0ptj4dlZJwZgNAtBYBnu5nNKJoW62m0zKcIEyVECrUKErkUkg6ajMy4ZfnVZciSBhg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-function-name@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.1.tgz#2ec76258c70fe08c6d7da154003a480620eba667" + integrity sha512-JF3UgJUILoFrFMEnOJLJkRHSk6LUSXLmEFsA23aR2O5CSLUxbeUX1IZ1YQ7Sn0aXb601Ncwjx73a+FVqgcljVw== + dependencies: + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-literals@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.1.tgz#d73b803a26b37017ddf9d3bb8f4dc58bfb806f57" + integrity sha512-+PxVGA+2Ag6uGgL0A5f+9rklOnnMccwEBzwYFL3EUaKuiyVnUipyXncFcfjSkbimLrODoqki1U9XxZzTvfN7IQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-member-expression-literals@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.1.tgz#496038602daf1514a64d43d8e17cbb2755e0c3ad" + integrity sha512-1sxePl6z9ad0gFMB9KqmYofk34flq62aqMt9NqliS/7hPEpURUCMbyHXrMPlo282iY7nAvUB1aQd5mg79UD9Jg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-modules-amd@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.12.1.tgz#3154300b026185666eebb0c0ed7f8415fefcf6f9" + integrity sha512-tDW8hMkzad5oDtzsB70HIQQRBiTKrhfgwC/KkJeGsaNFTdWhKNt/BiE8c5yj19XiGyrxpbkOfH87qkNg1YGlOQ== + dependencies: + "@babel/helper-module-transforms" "^7.12.1" + "@babel/helper-plugin-utils" "^7.10.4" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-commonjs@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.12.1.tgz#fa403124542636c786cf9b460a0ffbb48a86e648" + integrity sha512-dY789wq6l0uLY8py9c1B48V8mVL5gZh/+PQ5ZPrylPYsnAvnEMjqsUXkuoDVPeVK+0VyGar+D08107LzDQ6pag== + dependencies: + "@babel/helper-module-transforms" "^7.12.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-simple-access" "^7.12.1" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-systemjs@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.12.1.tgz#663fea620d593c93f214a464cd399bf6dc683086" + integrity sha512-Hn7cVvOavVh8yvW6fLwveFqSnd7rbQN3zJvoPNyNaQSvgfKmDBO9U1YL9+PCXGRlZD9tNdWTy5ACKqMuzyn32Q== + dependencies: + "@babel/helper-hoist-variables" "^7.10.4" + "@babel/helper-module-transforms" "^7.12.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-validator-identifier" "^7.10.4" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-umd@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.12.1.tgz#eb5a218d6b1c68f3d6217b8fa2cc82fec6547902" + integrity sha512-aEIubCS0KHKM0zUos5fIoQm+AZUMt1ZvMpqz0/H5qAQ7vWylr9+PLYurT+Ic7ID/bKLd4q8hDovaG3Zch2uz5Q== + dependencies: + "@babel/helper-module-transforms" "^7.12.1" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.1.tgz#b407f5c96be0d9f5f88467497fa82b30ac3e8753" + integrity sha512-tB43uQ62RHcoDp9v2Nsf+dSM8sbNodbEicbQNA53zHz8pWUhsgHSJCGpt7daXxRydjb0KnfmB+ChXOv3oADp1Q== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.12.1" + +"@babel/plugin-transform-new-target@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.1.tgz#80073f02ee1bb2d365c3416490e085c95759dec0" + integrity sha512-+eW/VLcUL5L9IvJH7rT1sT0CzkdUTvPrXC2PXTn/7z7tXLBuKvezYbGdxD5WMRoyvyaujOq2fWoKl869heKjhw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-object-super@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.1.tgz#4ea08696b8d2e65841d0c7706482b048bed1066e" + integrity sha512-AvypiGJH9hsquNUn+RXVcBdeE3KHPZexWRdimhuV59cSoOt5kFBmqlByorAeUlGG2CJWd0U+4ZtNKga/TB0cAw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-replace-supers" "^7.12.1" + +"@babel/plugin-transform-parameters@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.12.1.tgz#d2e963b038771650c922eff593799c96d853255d" + integrity sha512-xq9C5EQhdPK23ZeCdMxl8bbRnAgHFrw5EOC3KJUsSylZqdkCaFEXxGSBuTSObOpiiHHNyb82es8M1QYgfQGfNg== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-property-literals@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.1.tgz#41bc81200d730abb4456ab8b3fbd5537b59adecd" + integrity sha512-6MTCR/mZ1MQS+AwZLplX4cEySjCpnIF26ToWo942nqn8hXSm7McaHQNeGx/pt7suI1TWOWMfa/NgBhiqSnX0cQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-regenerator@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.1.tgz#5f0a28d842f6462281f06a964e88ba8d7ab49753" + integrity sha512-gYrHqs5itw6i4PflFX3OdBPMQdPbF4bj2REIUxlMRUFk0/ZOAIpDFuViuxPjUL7YC8UPnf+XG7/utJvqXdPKng== + dependencies: + regenerator-transform "^0.14.2" + +"@babel/plugin-transform-reserved-words@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.1.tgz#6fdfc8cc7edcc42b36a7c12188c6787c873adcd8" + integrity sha512-pOnUfhyPKvZpVyBHhSBoX8vfA09b7r00Pmm1sH+29ae2hMTKVmSp4Ztsr8KBKjLjx17H0eJqaRC3bR2iThM54A== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-shorthand-properties@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.1.tgz#0bf9cac5550fce0cfdf043420f661d645fdc75e3" + integrity sha512-GFZS3c/MhX1OusqB1MZ1ct2xRzX5ppQh2JU1h2Pnfk88HtFTM+TWQqJNfwkmxtPQtb/s1tk87oENfXJlx7rSDw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-spread@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.12.1.tgz#527f9f311be4ec7fdc2b79bb89f7bf884b3e1e1e" + integrity sha512-vuLp8CP0BE18zVYjsEBZ5xoCecMK6LBMMxYzJnh01rxQRvhNhH1csMMmBfNo5tGpGO+NhdSNW2mzIvBu3K1fng== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-skip-transparent-expression-wrappers" "^7.12.1" + +"@babel/plugin-transform-sticky-regex@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.1.tgz#5c24cf50de396d30e99afc8d1c700e8bce0f5caf" + integrity sha512-CiUgKQ3AGVk7kveIaPEET1jNDhZZEl1RPMWdTBE1799bdz++SwqDHStmxfCtDfBhQgCl38YRiSnrMuUMZIWSUQ== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-regex" "^7.10.4" + +"@babel/plugin-transform-template-literals@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.12.1.tgz#b43ece6ed9a79c0c71119f576d299ef09d942843" + integrity sha512-b4Zx3KHi+taXB1dVRBhVJtEPi9h1THCeKmae2qP0YdUHIFhVjtpqqNfxeVAa1xeHVhAy4SbHxEwx5cltAu5apw== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-typeof-symbol@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.1.tgz#9ca6be343d42512fbc2e68236a82ae64bc7af78a" + integrity sha512-EPGgpGy+O5Kg5pJFNDKuxt9RdmTgj5sgrus2XVeMp/ZIbOESadgILUbm50SNpghOh3/6yrbsH+NB5+WJTmsA7Q== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-unicode-escapes@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.1.tgz#5232b9f81ccb07070b7c3c36c67a1b78f1845709" + integrity sha512-I8gNHJLIc7GdApm7wkVnStWssPNbSRMPtgHdmH3sRM1zopz09UWPS4x5V4n1yz/MIWTVnJ9sp6IkuXdWM4w+2Q== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-transform-unicode-regex@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.1.tgz#cc9661f61390db5c65e3febaccefd5c6ac3faecb" + integrity sha512-SqH4ClNngh/zGwHZOOQMTD+e8FGWexILV+ePMyiDJttAWRh5dhDL8rcl5lSgU3Huiq6Zn6pWTMvdPAb21Dwdyg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.12.1" + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/preset-env@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.12.1.tgz#9c7e5ca82a19efc865384bb4989148d2ee5d7ac2" + integrity sha512-H8kxXmtPaAGT7TyBvSSkoSTUK6RHh61So05SyEbpmr0MCZrsNYn7mGMzzeYoOUCdHzww61k8XBft2TaES+xPLg== + dependencies: + "@babel/compat-data" "^7.12.1" + "@babel/helper-compilation-targets" "^7.12.1" + "@babel/helper-module-imports" "^7.12.1" + "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-validator-option" "^7.12.1" + "@babel/plugin-proposal-async-generator-functions" "^7.12.1" + "@babel/plugin-proposal-class-properties" "^7.12.1" + "@babel/plugin-proposal-dynamic-import" "^7.12.1" + "@babel/plugin-proposal-export-namespace-from" "^7.12.1" + "@babel/plugin-proposal-json-strings" "^7.12.1" + "@babel/plugin-proposal-logical-assignment-operators" "^7.12.1" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.12.1" + "@babel/plugin-proposal-numeric-separator" "^7.12.1" + "@babel/plugin-proposal-object-rest-spread" "^7.12.1" + "@babel/plugin-proposal-optional-catch-binding" "^7.12.1" + "@babel/plugin-proposal-optional-chaining" "^7.12.1" + "@babel/plugin-proposal-private-methods" "^7.12.1" + "@babel/plugin-proposal-unicode-property-regex" "^7.12.1" + "@babel/plugin-syntax-async-generators" "^7.8.0" + "@babel/plugin-syntax-class-properties" "^7.12.1" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.0" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + "@babel/plugin-syntax-top-level-await" "^7.12.1" + "@babel/plugin-transform-arrow-functions" "^7.12.1" + "@babel/plugin-transform-async-to-generator" "^7.12.1" + "@babel/plugin-transform-block-scoped-functions" "^7.12.1" + "@babel/plugin-transform-block-scoping" "^7.12.1" + "@babel/plugin-transform-classes" "^7.12.1" + "@babel/plugin-transform-computed-properties" "^7.12.1" + "@babel/plugin-transform-destructuring" "^7.12.1" + "@babel/plugin-transform-dotall-regex" "^7.12.1" + "@babel/plugin-transform-duplicate-keys" "^7.12.1" + "@babel/plugin-transform-exponentiation-operator" "^7.12.1" + "@babel/plugin-transform-for-of" "^7.12.1" + "@babel/plugin-transform-function-name" "^7.12.1" + "@babel/plugin-transform-literals" "^7.12.1" + "@babel/plugin-transform-member-expression-literals" "^7.12.1" + "@babel/plugin-transform-modules-amd" "^7.12.1" + "@babel/plugin-transform-modules-commonjs" "^7.12.1" + "@babel/plugin-transform-modules-systemjs" "^7.12.1" + "@babel/plugin-transform-modules-umd" "^7.12.1" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.12.1" + "@babel/plugin-transform-new-target" "^7.12.1" + "@babel/plugin-transform-object-super" "^7.12.1" + "@babel/plugin-transform-parameters" "^7.12.1" + "@babel/plugin-transform-property-literals" "^7.12.1" + "@babel/plugin-transform-regenerator" "^7.12.1" + "@babel/plugin-transform-reserved-words" "^7.12.1" + "@babel/plugin-transform-shorthand-properties" "^7.12.1" + "@babel/plugin-transform-spread" "^7.12.1" + "@babel/plugin-transform-sticky-regex" "^7.12.1" + "@babel/plugin-transform-template-literals" "^7.12.1" + "@babel/plugin-transform-typeof-symbol" "^7.12.1" + "@babel/plugin-transform-unicode-escapes" "^7.12.1" + "@babel/plugin-transform-unicode-regex" "^7.12.1" + "@babel/preset-modules" "^0.1.3" + "@babel/types" "^7.12.1" + core-js-compat "^3.6.2" + semver "^5.5.0" + +"@babel/preset-modules@^0.1.3": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.4.tgz#362f2b68c662842970fdb5e254ffc8fc1c2e415e" + integrity sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/register@^7.12.1": + version "7.12.1" + resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.12.1.tgz#cdb087bdfc4f7241c03231f22e15d211acf21438" + integrity sha512-XWcmseMIncOjoydKZnWvWi0/5CUCD+ZYKhRwgYlWOrA8fGZ/FjuLRpqtIhLOVD/fvR1b9DQHtZPn68VvhpYf+Q== + dependencies: + find-cache-dir "^2.0.0" + lodash "^4.17.19" + make-dir "^2.1.0" + pirates "^4.0.0" + source-map-support "^0.5.16" + +"@babel/runtime@^7.8.4": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" + integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.10.4", "@babel/template@^7.3.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.4.tgz#3251996c4200ebc71d1a8fc405fba940f36ba278" + integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/parser" "^7.10.4" + "@babel/types" "^7.10.4" + +"@babel/traverse@^7.1.0", "@babel/traverse@^7.10.4", "@babel/traverse@^7.12.1", "@babel/traverse@^7.12.5", "@babel/traverse@^7.7.0": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.5.tgz#78a0c68c8e8a35e4cacfd31db8bb303d5606f095" + integrity sha512-xa15FbQnias7z9a62LwYAA5SZZPkHIXpd42C6uW68o8uTuua96FHZy1y61Va5P/i83FAAcMpW8+A/QayntzuqA== + dependencies: + "@babel/code-frame" "^7.10.4" + "@babel/generator" "^7.12.5" + "@babel/helper-function-name" "^7.10.4" + "@babel/helper-split-export-declaration" "^7.11.0" + "@babel/parser" "^7.12.5" + "@babel/types" "^7.12.5" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.19" + +"@babel/types@^7.0.0", "@babel/types@^7.10.4", "@babel/types@^7.10.5", "@babel/types@^7.11.0", "@babel/types@^7.12.1", "@babel/types@^7.12.5", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4", "@babel/types@^7.7.0": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.5.tgz#5d6b4590cfe90c0c8d7396c83ffd9fc28b5a6450" + integrity sha512-gyTcvz7JFa4V45C0Zklv//GmFOAal5fL23OWpBLqc4nZ4Yrz67s4kCNwSK1Gu0MXGTU8mRY3zJYtacLdKXlzig== + dependencies: + "@babel/helper-validator-identifier" "^7.10.4" + lodash "^4.17.19" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@cnakazawa/watch@^1.0.3": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" + integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ== + dependencies: + exec-sh "^0.3.2" + minimist "^1.2.0" + +"@eslint/eslintrc@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.2.1.tgz#f72069c330461a06684d119384435e12a5d76e3c" + integrity sha512-XRUeBZ5zBWLYgSANMpThFddrZZkEbGHgUdt5UJjZfnlN9BGCiUBrf+nvbRupSjMvqzwnQN0qwCmOxITt1cfywA== + dependencies: + ajv "^6.12.4" + debug "^4.1.1" + espree "^7.3.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^3.13.1" + lodash "^4.17.19" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" + integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== + +"@jest/console@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.6.2.tgz#4e04bc464014358b03ab4937805ee36a0aeb98f2" + integrity sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g== + dependencies: + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^26.6.2" + jest-util "^26.6.2" + slash "^3.0.0" + +"@jest/core@^26.6.3": + version "26.6.3" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.6.3.tgz#7639fcb3833d748a4656ada54bde193051e45fad" + integrity sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw== + dependencies: + "@jest/console" "^26.6.2" + "@jest/reporters" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.4" + jest-changed-files "^26.6.2" + jest-config "^26.6.3" + jest-haste-map "^26.6.2" + jest-message-util "^26.6.2" + jest-regex-util "^26.0.0" + jest-resolve "^26.6.2" + jest-resolve-dependencies "^26.6.3" + jest-runner "^26.6.3" + jest-runtime "^26.6.3" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" + jest-watcher "^26.6.2" + micromatch "^4.0.2" + p-each-series "^2.1.0" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.6.2.tgz#ba364cc72e221e79cc8f0a99555bf5d7577cf92c" + integrity sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA== + dependencies: + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" + +"@jest/fake-timers@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.6.2.tgz#459c329bcf70cee4af4d7e3f3e67848123535aad" + integrity sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA== + dependencies: + "@jest/types" "^26.6.2" + "@sinonjs/fake-timers" "^6.0.1" + "@types/node" "*" + jest-message-util "^26.6.2" + jest-mock "^26.6.2" + jest-util "^26.6.2" + +"@jest/globals@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.6.2.tgz#5b613b78a1aa2655ae908eba638cc96a20df720a" + integrity sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA== + dependencies: + "@jest/environment" "^26.6.2" + "@jest/types" "^26.6.2" + expect "^26.6.2" + +"@jest/reporters@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.6.2.tgz#1f518b99637a5f18307bd3ecf9275f6882a667f6" + integrity sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.2.4" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^4.0.3" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.0.2" + jest-haste-map "^26.6.2" + jest-resolve "^26.6.2" + jest-util "^26.6.2" + jest-worker "^26.6.2" + slash "^3.0.0" + source-map "^0.6.0" + string-length "^4.0.1" + terminal-link "^2.0.0" + v8-to-istanbul "^7.0.0" + optionalDependencies: + node-notifier "^8.0.0" + +"@jest/source-map@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.6.2.tgz#29af5e1e2e324cafccc936f218309f54ab69d535" + integrity sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA== + dependencies: + callsites "^3.0.0" + graceful-fs "^4.2.4" + source-map "^0.6.0" + +"@jest/test-result@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.6.2.tgz#55da58b62df134576cc95476efa5f7949e3f5f18" + integrity sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ== + dependencies: + "@jest/console" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^26.6.3": + version "26.6.3" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz#98e8a45100863886d074205e8ffdc5a7eb582b17" + integrity sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw== + dependencies: + "@jest/test-result" "^26.6.2" + graceful-fs "^4.2.4" + jest-haste-map "^26.6.2" + jest-runner "^26.6.3" + jest-runtime "^26.6.3" + +"@jest/transform@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.6.2.tgz#5ac57c5fa1ad17b2aae83e73e45813894dcf2e4b" + integrity sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA== + dependencies: + "@babel/core" "^7.1.0" + "@jest/types" "^26.6.2" + babel-plugin-istanbul "^6.0.0" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.4" + jest-haste-map "^26.6.2" + jest-regex-util "^26.0.0" + jest-util "^26.6.2" + micromatch "^4.0.2" + pirates "^4.0.1" + slash "^3.0.0" + source-map "^0.6.1" + write-file-atomic "^3.0.0" + +"@jest/types@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" + integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^15.0.0" + chalk "^4.0.0" + +"@nodelib/fs.scandir@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" + integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw== + dependencies: + "@nodelib/fs.stat" "2.0.3" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" + integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" + integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ== + dependencies: + "@nodelib/fs.scandir" "2.1.3" + fastq "^1.6.0" + +"@sinonjs/commons@^1.7.0": + version "1.8.1" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.1.tgz#e7df00f98a203324f6dc7cc606cad9d4a8ab2217" + integrity sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40" + integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA== + dependencies: + "@sinonjs/commons" "^1.7.0" + +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7": + version "7.1.12" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.12.tgz#4d8e9e51eb265552a7e4f1ff2219ab6133bdfb2d" + integrity sha512-wMTHiiTiBAAPebqaPiPDLFA4LYPKr6Ph0Xq/6rq1Ur3v66HXyG+clfR9CNETkD7MQS8ZHvpQOtA53DLws5WAEQ== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.2" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.2.tgz#f3d71178e187858f7c45e30380f8f1b7415a12d8" + integrity sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.0.3" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.0.3.tgz#b8aaeba0a45caca7b56a5de9459872dde3727214" + integrity sha512-uCoznIPDmnickEi6D0v11SBpW0OuVqHJCa7syXqQHy5uktSCreIlt0iglsCnmvz8yCb38hGcWeseA8cWJSwv5Q== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.0.15.tgz#db9e4238931eb69ef8aab0ad6523d4d4caa39d03" + integrity sha512-Pzh9O3sTK8V6I1olsXpCfj2k/ygO2q1X0vhhnDrEQyYLHZesWz+zMZMVcwXLCYf0U36EtmyYaFGPfXlTtDHe3A== + dependencies: + "@babel/types" "^7.3.0" + +"@types/graceful-fs@^4.1.2": + version "4.1.4" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.4.tgz#4ff9f641a7c6d1a3508ff88bc3141b152772e753" + integrity sha512-mWA/4zFQhfvOA8zWkXobwJvBD7vzcxgrOQ0J5CH1votGqdq9m7+FwtGaqyCZqC3NyyBkc9z4m+iry4LlqcMWJg== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" + integrity sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz#508b13aa344fa4976234e75dddcc34925737d821" + integrity sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/json-schema@^7.0.3": + version "7.0.6" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0" + integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw== + +"@types/node@*": + version "14.14.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.6.tgz#146d3da57b3c636cc0d1769396ce1cfa8991147f" + integrity sha512-6QlRuqsQ/Ox/aJEQWBEJG7A9+u7oSYl3mem/K8IzxXG/kAGbV1YPD9Bg9Zw3vyxC/YP+zONKwy8hGkSt1jxFMw== + +"@types/normalize-package-data@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" + integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== + +"@types/prettier@^2.0.0": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.1.5.tgz#b6ab3bba29e16b821d84e09ecfaded462b816b00" + integrity sha512-UEyp8LwZ4Dg30kVU2Q3amHHyTn1jEdhCIE59ANed76GaT1Vp76DD3ZWSAxgCrw6wJ0TqeoBpqmfUHiUDPs//HQ== + +"@types/stack-utils@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.0.tgz#7036640b4e21cc2f259ae826ce843d277dad8cff" + integrity sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw== + +"@types/yargs-parser@*": + version "15.0.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d" + integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw== + +"@types/yargs@^15.0.0": + version "15.0.9" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.9.tgz#524cd7998fe810cdb02f26101b699cccd156ff19" + integrity sha512-HmU8SeIRhZCWcnRskCs36Q1Q00KBV6Cqh/ora8WN1+22dY07AZdn6Gel8QZ3t26XYPImtcL8WV/eqjhVmMEw4g== + dependencies: + "@types/yargs-parser" "*" + +"@typescript-eslint/experimental-utils@^4.0.1": + version "4.6.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.6.1.tgz#a9c691dfd530a9570274fe68907c24c07a06c4aa" + integrity sha512-qyPqCFWlHZXkEBoV56UxHSoXW2qnTr4JrWVXOh3soBP3q0o7p4pUEMfInDwIa0dB/ypdtm7gLOS0hg0a73ijfg== + dependencies: + "@types/json-schema" "^7.0.3" + "@typescript-eslint/scope-manager" "4.6.1" + "@typescript-eslint/types" "4.6.1" + "@typescript-eslint/typescript-estree" "4.6.1" + eslint-scope "^5.0.0" + eslint-utils "^2.0.0" + +"@typescript-eslint/scope-manager@4.6.1": + version "4.6.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.6.1.tgz#21872b91cbf7adfc7083f17b8041149148baf992" + integrity sha512-f95+80r6VdINYscJY1KDUEDcxZ3prAWHulL4qRDfNVD0I5QAVSGqFkwHERDoLYJJWmEAkUMdQVvx7/c2Hp+Bjg== + dependencies: + "@typescript-eslint/types" "4.6.1" + "@typescript-eslint/visitor-keys" "4.6.1" + +"@typescript-eslint/types@4.6.1": + version "4.6.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.6.1.tgz#d3ad7478f53f22e7339dc006ab61aac131231552" + integrity sha512-k2ZCHhJ96YZyPIsykickez+OMHkz06xppVLfJ+DY90i532/Cx2Z+HiRMH8YZQo7a4zVd/TwNBuRCdXlGK4yo8w== + +"@typescript-eslint/typescript-estree@4.6.1": + version "4.6.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.6.1.tgz#6025cce724329413f57e4959b2d676fceeca246f" + integrity sha512-/J/kxiyjQQKqEr5kuKLNQ1Finpfb8gf/NpbwqFFYEBjxOsZ621r9AqwS9UDRA1Rrr/eneX/YsbPAIhU2rFLjXQ== + dependencies: + "@typescript-eslint/types" "4.6.1" + "@typescript-eslint/visitor-keys" "4.6.1" + debug "^4.1.1" + globby "^11.0.1" + is-glob "^4.0.1" + lodash "^4.17.15" + semver "^7.3.2" + tsutils "^3.17.1" + +"@typescript-eslint/visitor-keys@4.6.1": + version "4.6.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.6.1.tgz#6b125883402d8939df7b54528d879e88f7ba3614" + integrity sha512-owABze4toX7QXwOLT3/D5a8NecZEjEWU1srqxENTfqsY3bwVnl3YYbOh6s1rp2wQKO9RTHFGjKes08FgE7SVMw== + dependencies: + "@typescript-eslint/types" "4.6.1" + eslint-visitor-keys "^2.0.0" + +JSONStream@^1.0.3: + version "1.3.5" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" + integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + +abab@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" + integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== + +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +accepts@~1.3.4: + version "1.3.7" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" + integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== + dependencies: + mime-types "~2.1.24" + negotiator "0.6.2" + +acorn-globals@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" + integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== + dependencies: + acorn "^7.1.1" + acorn-walk "^7.1.1" + +acorn-jsx@^5.2.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" + integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng== + +acorn-node@^1.2.0, acorn-node@^1.3.0, acorn-node@^1.5.2, acorn-node@^1.6.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8" + integrity sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A== + dependencies: + acorn "^7.0.0" + acorn-walk "^7.0.0" + xtend "^4.0.2" + +acorn-walk@^7.0.0, acorn-walk@^7.1.1: + version "7.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== + +acorn@^7.0.0, acorn@^7.1.1, acorn@^7.4.0: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +after@0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" + integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= + +ansi-colors@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-1.1.0.tgz#6374b4dd5d4718ff3ce27a671a3b1cad077132a9" + integrity sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA== + dependencies: + ansi-wrap "^0.1.0" + +ansi-colors@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-2.0.5.tgz#5da37825fef3e75f3bda47f760d64bfd10e15e10" + integrity sha512-yAdfUZ+c2wetVNIFsNRn44THW+Lty6S5TwMpUfLA/UaGhiXbBv/F8E60/1hMLd0cnF/CDoWH8vzVaI5bAcHCjw== + +ansi-colors@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + +ansi-escapes@^4.2.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" + integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA== + dependencies: + type-fest "^0.11.0" + +ansi-gray@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251" + integrity sha1-KWLPVOyXksSFEKPetSRDaGHvclE= + dependencies: + ansi-wrap "0.1.0" + +ansi-regex@^2.0.0, ansi-regex@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= + +ansi-regex@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== + +ansi-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= + +ansi-styles@^3.2.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178" + integrity sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg= + +ansi-wrap@0.1.0, ansi-wrap@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" + integrity sha1-qCJQ3bABXponyoLoLqYDu/pF768= + +any-promise@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= + +anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + +anymatch@^3.0.3, anymatch@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" + integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +append-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/append-buffer/-/append-buffer-1.0.2.tgz#d8220cf466081525efea50614f3de6514dfa58f1" + integrity sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE= + dependencies: + buffer-equal "^1.0.0" + +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +archy@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" + integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + +arr-filter@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/arr-filter/-/arr-filter-1.1.2.tgz#43fdddd091e8ef11aa4c45d9cdc18e2dff1711ee" + integrity sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4= + dependencies: + make-iterator "^1.0.0" + +arr-flatten@^1.0.1, arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + +arr-map@^2.0.0, arr-map@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/arr-map/-/arr-map-2.0.2.tgz#3a77345ffc1cf35e2a91825601f9e58f2e24cac4" + integrity sha1-Onc0X/wc814qkYJWAfnljy4kysQ= + dependencies: + make-iterator "^1.0.0" + +arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + +array-differ@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031" + integrity sha1-7/UuN1gknTO+QCuLuOVkuytdQDE= + +array-each@^1.0.0, array-each@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/array-each/-/array-each-1.0.1.tgz#a794af0c05ab1752846ee753a1f211a05ba0c44f" + integrity sha1-p5SvDAWrF1KEbudTofIRoFugxE8= + +array-filter@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83" + integrity sha1-uveeYubvTCpMC4MSMtr/7CUfnYM= + +array-find-index@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= + +array-initial@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/array-initial/-/array-initial-1.1.0.tgz#2fa74b26739371c3947bd7a7adc73be334b3d795" + integrity sha1-L6dLJnOTccOUe9enrcc74zSz15U= + dependencies: + array-slice "^1.0.0" + is-number "^4.0.0" + +array-last@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/array-last/-/array-last-1.3.0.tgz#7aa77073fec565ddab2493f5f88185f404a9d336" + integrity sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg== + dependencies: + is-number "^4.0.0" + +array-slice@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-1.1.0.tgz#e368ea15f89bc7069f7ffb89aec3a6c7d4ac22d4" + integrity sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w== + +array-sort@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-sort/-/array-sort-1.0.0.tgz#e4c05356453f56f53512a7d1d6123f2c54c0a88a" + integrity sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg== + dependencies: + default-compare "^1.0.0" + get-value "^2.0.6" + kind-of "^5.0.2" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array-uniq@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= + +array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + +arraybuffer.slice@~0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" + integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog== + +arrify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" + integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== + +asn1.js@^5.2.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" + integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + safer-buffer "^2.1.0" + +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + +assert@^1.4.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" + integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== + dependencies: + object-assign "^4.1.1" + util "0.10.3" + +assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + +astral-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" + integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== + +async-done@^1.2.0, async-done@^1.2.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/async-done/-/async-done-1.3.2.tgz#5e15aa729962a4b07414f528a88cdf18e0b290a2" + integrity sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.2" + process-nextick-args "^2.0.0" + stream-exhaust "^1.0.1" + +async-each-series@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/async-each-series/-/async-each-series-0.1.1.tgz#7617c1917401fd8ca4a28aadce3dbae98afeb432" + integrity sha1-dhfBkXQB/Yykooqtzj266Yr+tDI= + +async-each@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== + +async-foreach@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" + integrity sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI= + +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + +async-settle@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-settle/-/async-settle-1.0.0.tgz#1d0a914bb02575bec8a8f3a74e5080f72b2c0c6b" + integrity sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs= + dependencies: + async-done "^1.2.2" + +async@1.5.2, async@^1.5.0: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +atob@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + +autoprefixer@^9.6.1: + version "9.8.6" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f" + integrity sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg== + dependencies: + browserslist "^4.12.0" + caniuse-lite "^1.0.30001109" + colorette "^1.2.1" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + postcss "^7.0.32" + postcss-value-parser "^4.1.0" + +available-typed-arrays@^1.0.0, available-typed-arrays@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz#6b098ca9d8039079ee3f77f7b783c4480ba513f5" + integrity sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ== + dependencies: + array-filter "^1.0.0" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.8.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" + integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== + +axios@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.0.tgz#8e09bff3d9122e133f7b8101c8fbdd00ed3d2ab8" + integrity sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ== + dependencies: + follow-redirects "1.5.10" + is-buffer "^2.0.2" + +babel-eslint@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.1.0.tgz#6968e568a910b78fb3779cdd8b6ac2f479943232" + integrity sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.7.0" + "@babel/traverse" "^7.7.0" + "@babel/types" "^7.7.0" + eslint-visitor-keys "^1.0.0" + resolve "^1.12.0" + +babel-jest@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.6.3.tgz#d87d25cb0037577a0c89f82e5755c5d293c01056" + integrity sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA== + dependencies: + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/babel__core" "^7.1.7" + babel-plugin-istanbul "^6.0.0" + babel-preset-jest "^26.6.2" + chalk "^4.0.0" + graceful-fs "^4.2.4" + slash "^3.0.0" + +babel-plugin-dynamic-import-node@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" + integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== + dependencies: + object.assign "^4.1.0" + +babel-plugin-istanbul@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765" + integrity sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^4.0.0" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz#8185bd030348d254c6d7dd974355e6a28b21e62d" + integrity sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" + "@types/babel__traverse" "^7.0.6" + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.0.tgz#cf5feef29551253471cfa82fc8e0f5063df07a77" + integrity sha512-mGkvkpocWJes1CmMKtgGUwCeeq0pOhALyymozzDWYomHTbDLwueDYG6p4TK1YOeYHCzBzYPsWkgTto10JubI1Q== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz#747872b1171df032252426586881d62d31798fee" + integrity sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ== + dependencies: + babel-plugin-jest-hoist "^26.6.2" + babel-preset-current-node-syntax "^1.0.0" + +bach@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/bach/-/bach-1.2.0.tgz#4b3ce96bf27134f79a1b414a51c14e34c3bd9880" + integrity sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA= + dependencies: + arr-filter "^1.1.1" + arr-flatten "^1.0.1" + arr-map "^2.0.0" + array-each "^1.0.0" + array-initial "^1.0.0" + array-last "^1.1.1" + async-done "^1.2.2" + async-settle "^1.0.0" + now-and-later "^2.0.0" + +backo2@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= + +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + +base64-arraybuffer@0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz#9818c79e059b1355f97e0428a017c838e90ba812" + integrity sha1-mBjHngWbE1X5fgQooBfIOOkLqBI= + +base64-arraybuffer@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg= + +base64-js@^1.0.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" + integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== + +base64id@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" + integrity sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY= + +base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + +beeper@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809" + integrity sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak= + +better-assert@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + integrity sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI= + dependencies: + callsite "1.0.0" + +binary-extensions@^1.0.0: + version "1.13.1" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== + +binary-extensions@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9" + integrity sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ== + +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +blob@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" + integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig== + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= + dependencies: + inherits "~2.0.0" + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.4.0: + version "4.11.9" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828" + integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw== + +bn.js@^5.1.1: + version "5.1.3" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.3.tgz#beca005408f642ebebea80b042b4d18d2ac0ee6b" + integrity sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ== + +body@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/body/-/body-5.1.0.tgz#e4ba0ce410a46936323367609ecb4e6553125069" + integrity sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk= + dependencies: + continuable-cache "^0.3.1" + error "^7.0.0" + raw-body "~1.1.0" + safe-json-parse "~1.0.1" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@^2.3.1, braces@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + +braces@^3.0.1, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + +browser-pack@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/browser-pack/-/browser-pack-6.1.0.tgz#c34ba10d0b9ce162b5af227c7131c92c2ecd5774" + integrity sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA== + dependencies: + JSONStream "^1.0.3" + combine-source-map "~0.8.0" + defined "^1.0.0" + safe-buffer "^5.1.1" + through2 "^2.0.0" + umd "^3.0.0" + +browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== + +browser-resolve@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-2.0.0.tgz#99b7304cb392f8d73dba741bb2d7da28c6d7842b" + integrity sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ== + dependencies: + resolve "^1.17.0" + +browser-sync-client@^2.26.13: + version "2.26.13" + resolved "https://registry.yarnpkg.com/browser-sync-client/-/browser-sync-client-2.26.13.tgz#ee5fa3ec36fe2a03f9887553cac6846751c8232d" + integrity sha512-p2VbZoYrpuDhkreq+/Sv1MkToHklh7T1OaIntDwpG6Iy2q/XkBcgwPcWjX+WwRNiZjN8MEehxIjEUh12LweLmQ== + dependencies: + etag "1.8.1" + fresh "0.5.2" + mitt "^1.1.3" + rxjs "^5.5.6" + +browser-sync-ui@^2.26.13: + version "2.26.13" + resolved "https://registry.yarnpkg.com/browser-sync-ui/-/browser-sync-ui-2.26.13.tgz#7a0622df2c1cc4fb0dd8edd511f90737f84239b4" + integrity sha512-6NJ/pCnhCnBMzaty1opWo7ipDmFAIk8U71JMQGKJxblCUaGfdsbF2shf6XNZSkXYia1yS0vwKu9LIOzpXqQZCA== + dependencies: + async-each-series "0.1.1" + connect-history-api-fallback "^1" + immutable "^3" + server-destroy "1.0.1" + socket.io-client "^2.0.4" + stream-throttle "^0.1.3" + +browser-sync@^2.26.13: + version "2.26.13" + resolved "https://registry.yarnpkg.com/browser-sync/-/browser-sync-2.26.13.tgz#a74541c104aec7eda318a5d8abdb3317ae9eda3d" + integrity sha512-JPYLTngIzI+Dzx+StSSlMtF+Q9yjdh58HW6bMFqkFXuzQkJL8FCvp4lozlS6BbECZcsM2Gmlgp0uhEjvl18X4w== + dependencies: + browser-sync-client "^2.26.13" + browser-sync-ui "^2.26.13" + bs-recipes "1.3.4" + bs-snippet-injector "^2.0.1" + chokidar "^3.4.1" + connect "3.6.6" + connect-history-api-fallback "^1" + dev-ip "^1.0.1" + easy-extender "^2.3.4" + eazy-logger "3.1.0" + etag "^1.8.1" + fresh "^0.5.2" + fs-extra "3.0.1" + http-proxy "^1.18.1" + immutable "^3" + localtunnel "^2.0.0" + micromatch "^4.0.2" + opn "5.3.0" + portscanner "2.1.1" + qs "6.2.3" + raw-body "^2.3.2" + resp-modifier "6.0.2" + rx "4.1.0" + send "0.16.2" + serve-index "1.9.1" + serve-static "1.13.2" + server-destroy "1.0.1" + socket.io "2.1.1" + ua-parser-js "^0.7.18" + yargs "^15.4.1" + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ= + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" + integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== + dependencies: + bn.js "^5.1.1" + browserify-rsa "^4.0.1" + create-hash "^1.2.0" + create-hmac "^1.1.7" + elliptic "^6.5.3" + inherits "^2.0.4" + parse-asn1 "^5.1.5" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +browserify-transform-tools@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/browserify-transform-tools/-/browserify-transform-tools-1.7.0.tgz#83e277221f63259bed2e7eb2a283a970a501f4c4" + integrity sha1-g+J3Ih9jJZvtLn6yooOpcKUB9MQ= + dependencies: + falafel "^2.0.0" + through "^2.3.7" + +browserify-zlib@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== + dependencies: + pako "~1.0.5" + +browserify@^17.0.0: + version "17.0.0" + resolved "https://registry.yarnpkg.com/browserify/-/browserify-17.0.0.tgz#4c48fed6c02bfa2b51fd3b670fddb805723cdc22" + integrity sha512-SaHqzhku9v/j6XsQMRxPyBrSP3gnwmE27gLJYZgMT2GeK3J0+0toN+MnuNYDfHwVGQfLiMZ7KSNSIXHemy905w== + dependencies: + JSONStream "^1.0.3" + assert "^1.4.0" + browser-pack "^6.0.1" + browser-resolve "^2.0.0" + browserify-zlib "~0.2.0" + buffer "~5.2.1" + cached-path-relative "^1.0.0" + concat-stream "^1.6.0" + console-browserify "^1.1.0" + constants-browserify "~1.0.0" + crypto-browserify "^3.0.0" + defined "^1.0.0" + deps-sort "^2.0.1" + domain-browser "^1.2.0" + duplexer2 "~0.1.2" + events "^3.0.0" + glob "^7.1.0" + has "^1.0.0" + htmlescape "^1.1.0" + https-browserify "^1.0.0" + inherits "~2.0.1" + insert-module-globals "^7.2.1" + labeled-stream-splicer "^2.0.0" + mkdirp-classic "^0.5.2" + module-deps "^6.2.3" + os-browserify "~0.3.0" + parents "^1.0.1" + path-browserify "^1.0.0" + process "~0.11.0" + punycode "^1.3.2" + querystring-es3 "~0.2.0" + read-only-stream "^2.0.0" + readable-stream "^2.0.2" + resolve "^1.1.4" + shasum-object "^1.0.0" + shell-quote "^1.6.1" + stream-browserify "^3.0.0" + stream-http "^3.0.0" + string_decoder "^1.1.1" + subarg "^1.0.0" + syntax-error "^1.1.1" + through2 "^2.0.0" + timers-browserify "^1.0.1" + tty-browserify "0.0.1" + url "~0.11.0" + util "~0.12.0" + vm-browserify "^1.0.0" + xtend "^4.0.0" + +browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.8.5: + version "4.14.6" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.14.6.tgz#97702a9c212e0c6b6afefad913d3a1538e348457" + integrity sha512-zeFYcUo85ENhc/zxHbiIp0LGzzTrE2Pv2JhxvS7kpUb9Q9D38kUX6Bie7pGutJ/5iF5rOxE7CepAuWD56xJ33A== + dependencies: + caniuse-lite "^1.0.30001154" + electron-to-chromium "^1.3.585" + escalade "^3.1.1" + node-releases "^1.1.65" + +bs-recipes@1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/bs-recipes/-/bs-recipes-1.3.4.tgz#0d2d4d48a718c8c044769fdc4f89592dc8b69585" + integrity sha1-DS1NSKcYyMBEdp/cT4lZLci2lYU= + +bs-snippet-injector@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/bs-snippet-injector/-/bs-snippet-injector-2.0.1.tgz#61b5393f11f52559ed120693100343b6edb04dd5" + integrity sha1-YbU5PxH1JVntEgaTEANDtu2wTdU= + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.0.tgz#59616b498304d556abd466966b22eeda3eca5fbe" + integrity sha1-WWFrSYME1Var1GaWayLu2j7KX74= + +buffer-from@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= + +buffer@~5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.2.1.tgz#dd57fa0f109ac59c602479044dca7b8b3d0b71d6" + integrity sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + +buffers@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" + integrity sha1-skV5w77U1tOWru5tmorn9Ugqt7s= + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= + +bytes@1: + version "1.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-1.0.0.tgz#3569ede8ba34315fab99c3e92cb04c7220de1fa8" + integrity sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g= + +bytes@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" + integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== + +cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + 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" + +cached-path-relative@^1.0.0, cached-path-relative@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cached-path-relative/-/cached-path-relative-1.0.2.tgz#a13df4196d26776220cc3356eb147a52dba2c6db" + integrity sha512-5r2GqsoEb4qMTTN9J+WzXfjov+hjxT+j3u5K+kIVNIwAd99DLCJE9pBIMP1qVeybV6JiijL385Oz0DcYxfbOIg== + +call-bind@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.0.tgz#24127054bb3f9bdcb4b1fb82418186072f77b8ce" + integrity sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.0" + +callsite@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA= + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camel-case@3.0.x: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" + integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M= + dependencies: + no-case "^2.2.0" + upper-case "^1.1.1" + +camelcase-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc= + dependencies: + camelcase "^2.0.0" + map-obj "^1.0.0" + +camelcase@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= + +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= + +camelcase@^5.0.0, camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.0.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" + integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== + +caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001154: + version "1.0.30001271" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001271.tgz" + integrity sha512-BBruZFWmt3HFdVPS8kceTBIguKxu4f99n5JNp06OlPD/luoAMIaIK5ieV5YjnBLH3Nysai9sxj9rpJj4ZisXOA== + +capture-exit@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" + integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== + dependencies: + rsvp "^4.8.4" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + +chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^2.0.0, chalk@^2.3.0, chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" + integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f" + integrity sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8= + dependencies: + ansi-styles "~1.0.0" + has-color "~0.1.0" + strip-ansi "~0.1.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +chokidar@^2.0.0: + version "2.1.8" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" + integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.1" + braces "^2.3.2" + glob-parent "^3.1.0" + inherits "^2.0.3" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^3.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.2.1" + upath "^1.1.1" + optionalDependencies: + fsevents "^1.2.7" + +chokidar@^3.4.1: + version "3.4.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.3.tgz#c1df38231448e45ca4ac588e6c79573ba6a57d5b" + integrity sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ== + dependencies: + anymatch "~3.1.1" + braces "~3.0.2" + glob-parent "~5.1.0" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.5.0" + optionalDependencies: + fsevents "~2.1.2" + +ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +cjs-module-lexer@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz#4186fcca0eae175970aee870b9fe2d6cf8d5655f" + integrity sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw== + +class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + +clean-css@4.2.3, clean-css@4.2.x: + version "4.2.3" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.3.tgz#507b5de7d97b48ee53d84adb0160ff6216380f78" + integrity sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA== + dependencies: + source-map "~0.6.0" + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cli-color@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/cli-color/-/cli-color-1.4.0.tgz#7d10738f48526824f8fe7da51857cb0f572fe01f" + integrity sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w== + dependencies: + ansi-regex "^2.1.1" + d "1" + es5-ext "^0.10.46" + es6-iterator "^2.0.3" + memoizee "^0.4.14" + timers-ext "^0.1.5" + +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + +cliui@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" + integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^6.2.0" + +clone-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" + integrity sha1-4+JbIHrE5wGvch4staFnksrD3Fg= + +clone-stats@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1" + integrity sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE= + +clone-stats@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680" + integrity sha1-s3gt/4u1R04Yuba/D9/ngvh3doA= + +clone@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + +clone@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= + +cloneable-readable@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.3.tgz#120a00cb053bfb63a222e709f9683ea2e11d8cec" + integrity sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ== + dependencies: + inherits "^2.0.1" + process-nextick-args "^2.0.0" + readable-stream "^2.3.5" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +collect-v8-coverage@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" + integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== + +collection-map@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-map/-/collection-map-1.0.0.tgz#aea0f06f8d26c780c2b75494385544b2255af18c" + integrity sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw= + dependencies: + arr-map "^2.0.2" + for-own "^1.0.0" + make-iterator "^1.0.0" + +collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-support@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + +colorette@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b" + integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw== + +combine-source-map@^0.8.0, combine-source-map@~0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/combine-source-map/-/combine-source-map-0.8.0.tgz#a58d0df042c186fcf822a8e8015f5450d2d79a8b" + integrity sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos= + dependencies: + convert-source-map "~1.1.0" + inline-source-map "~0.6.0" + lodash.memoize "~3.0.3" + source-map "~0.5.3" + +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@2.17.x: + version "2.17.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" + integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== + +commander@^2.2.0, commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@~2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" + integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= + +component-bind@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E= + +component-emitter@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= + +component-emitter@^1.2.1, component-emitter@~1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + +component-inherit@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM= + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +concat-stream@^1.6.0, concat-stream@^1.6.1, concat-stream@~1.6.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +concat-with-sourcemaps@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz#d4ea93f05ae25790951b99e7b3b09e3908a4082e" + integrity sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg== + dependencies: + source-map "^0.6.1" + +connect-history-api-fallback@^1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" + integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== + +connect-livereload@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/connect-livereload/-/connect-livereload-0.6.1.tgz#1ac0c8bb9d9cfd5b28b629987a56a9239db9baaa" + integrity sha512-3R0kMOdL7CjJpU66fzAkCe6HNtd3AavCS4m+uW4KtJjrdGPT0SQEZieAYd+cm+lJoBznNQ4lqipYWkhBMgk00g== + +connect@3.6.6: + version "3.6.6" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.6.tgz#09eff6c55af7236e137135a72574858b6786f524" + integrity sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ= + dependencies: + debug "2.6.9" + finalhandler "1.1.0" + parseurl "~1.3.2" + utils-merge "1.0.1" + +connect@^3.6.6: + version "3.7.0" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8" + integrity sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ== + dependencies: + debug "2.6.9" + finalhandler "1.1.2" + parseurl "~1.3.3" + utils-merge "1.0.1" + +console-browserify@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" + integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + +constants-browserify@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= + +continuable-cache@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/continuable-cache/-/continuable-cache-0.3.1.tgz#bd727a7faed77e71ff3985ac93351a912733ad0f" + integrity sha1-vXJ6f67XfnH/OYWskzUakSczrQ8= + +convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + dependencies: + safe-buffer "~5.1.1" + +convert-source-map@~1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860" + integrity sha1-SCnId+n+SbMWHzvzZziI4gRpmGA= + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= + +copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + +copy-props@^2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/copy-props/-/copy-props-2.0.4.tgz#93bb1cadfafd31da5bb8a9d4b41f471ec3a72dfe" + integrity sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A== + dependencies: + each-props "^1.3.0" + is-plain-object "^2.0.1" + +core-js-compat@^3.6.2: + version "3.6.5" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.5.tgz#2a51d9a4e25dfd6e690251aa81f99e3c05481f1c" + integrity sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng== + dependencies: + browserslist "^4.8.5" + semver "7.0.0" + +core-util-is@1.0.2, core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +create-ecdh@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" + integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== + dependencies: + bn.js "^4.1.0" + elliptic "^6.5.3" + +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" + integrity sha1-ElYDfsufDF9549bvE14wdwGEuYI= + dependencies: + lru-cache "^4.0.1" + which "^1.2.9" + +cross-spawn@^6.0.0: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + +cross-spawn@^7.0.0, cross-spawn@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +crypto-browserify@^3.0.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + +cssom@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" + integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== + +cssom@~0.3.6: + version "0.3.8" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + +cssstyle@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== + dependencies: + cssom "~0.3.6" + +currently-unhandled@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= + dependencies: + array-find-index "^1.0.1" + +d@1, d@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" + integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== + dependencies: + es5-ext "^0.10.50" + type "^1.0.1" + +dash-ast@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/dash-ast/-/dash-ast-1.0.0.tgz#12029ba5fb2f8aa6f0a861795b23c1b4b6c27d37" + integrity sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA== + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +data-urls@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" + integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== + dependencies: + abab "^2.0.3" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.0.0" + +dateformat@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.2.0.tgz#4065e2013cf9fb916ddfd82efb506ad4c6769062" + integrity sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI= + +debug@2.6.9, debug@^2.2.0, debug@^2.3.3: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" + integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== + dependencies: + ms "^2.1.1" + +debug@=3.1.0, debug@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + +debug@^3.1.0: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.2.0.tgz#7f150f93920e94c58f5574c2fd01a3110effe7f1" + integrity sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg== + dependencies: + ms "2.1.2" + +decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + +decimal.js@^10.2.0: + version "10.2.1" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.2.1.tgz#238ae7b0f0c793d3e3cea410108b35a2c01426a3" + integrity sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw== + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + +deep-is@^0.1.3, deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + +deepmerge@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + +default-compare@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/default-compare/-/default-compare-1.0.0.tgz#cb61131844ad84d84788fb68fd01681ca7781a2f" + integrity sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ== + dependencies: + kind-of "^5.0.2" + +default-resolution@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/default-resolution/-/default-resolution-2.0.0.tgz#bcb82baa72ad79b426a76732f1a81ad6df26d684" + integrity sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ= + +define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + +define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + +define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + +define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + +defined@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM= + +del@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/del/-/del-6.0.0.tgz#0b40d0332cea743f1614f818be4feb717714c952" + integrity sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ== + dependencies: + globby "^11.0.1" + graceful-fs "^4.2.4" + is-glob "^4.0.1" + is-path-cwd "^2.2.0" + is-path-inside "^3.0.2" + p-map "^4.0.0" + rimraf "^3.0.2" + slash "^3.0.0" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + +deps-sort@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/deps-sort/-/deps-sort-2.0.1.tgz#9dfdc876d2bcec3386b6829ac52162cda9fa208d" + integrity sha512-1orqXQr5po+3KI6kQb9A4jnXT1PBwggGl2d7Sq2xsnOeI9GPcE/tGcF9UiSZtZBM7MukY4cAh7MemS6tZYipfw== + dependencies: + JSONStream "^1.0.3" + shasum-object "^1.0.0" + subarg "^1.0.0" + through2 "^2.0.0" + +des.js@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" + integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + +detect-file@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" + integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +detective@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.0.tgz#feb2a77e85b904ecdea459ad897cc90a99bd2a7b" + integrity sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg== + dependencies: + acorn-node "^1.6.1" + defined "^1.0.0" + minimist "^1.1.1" + +dev-ip@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dev-ip/-/dev-ip-1.0.1.tgz#a76a3ed1855be7a012bb8ac16cb80f3c00dc28f0" + integrity sha1-p2o+0YVb56ASu4rBbLgPPADcKPA= + +diff-sequences@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" + integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== + +diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +dlv@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" + integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +domain-browser@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== + +domexception@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" + integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== + dependencies: + webidl-conversions "^5.0.0" + +duplexer2@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db" + integrity sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds= + dependencies: + readable-stream "~1.1.9" + +duplexer2@^0.1.2, duplexer2@~0.1.0, duplexer2@~0.1.2: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" + integrity sha1-ixLauHjA1p4+eJEFFmKjL8a93ME= + dependencies: + readable-stream "^2.0.2" + +duplexify@^3.6.0: + version "3.7.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" + integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + +duplexify@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-4.1.1.tgz#7027dc374f157b122a8ae08c2d3ea4d2d953aa61" + integrity sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA== + dependencies: + end-of-stream "^1.4.1" + inherits "^2.0.3" + readable-stream "^3.1.1" + stream-shift "^1.0.0" + +each-props@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/each-props/-/each-props-1.3.2.tgz#ea45a414d16dd5cfa419b1a81720d5ca06892333" + integrity sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA== + dependencies: + is-plain-object "^2.0.1" + object.defaults "^1.1.0" + +easy-extender@^2.3.4: + version "2.3.4" + resolved "https://registry.yarnpkg.com/easy-extender/-/easy-extender-2.3.4.tgz#298789b64f9aaba62169c77a2b3b64b4c9589b8f" + integrity sha512-8cAwm6md1YTiPpOvDULYJL4ZS6WfM5/cTeVVh4JsvyYZAoqlRVUpHL9Gr5Fy7HA6xcSZicUia3DeAgO3Us8E+Q== + dependencies: + lodash "^4.17.10" + +eazy-logger@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/eazy-logger/-/eazy-logger-3.1.0.tgz#b169eb56df714608fa114f164c8a2956bec9f0f3" + integrity sha512-/snsn2JqBtUSSstEl4R0RKjkisGHAhvYj89i7r3ytNUKW12y178KDZwXLXIgwDqLW6E/VRMT9qfld7wvFae8bQ== + dependencies: + tfunk "^4.0.0" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + +electron-to-chromium@^1.3.585: + version "1.3.587" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.587.tgz#de570df7320eb259c0511f284c2d6008094edbf7" + integrity sha512-8XFNxzNj0R8HpTQslWAw6UWpGSuOKSP3srhyFHVbGUGb8vTHckZGCyWi+iQlaXJx5DNeTQTQLd6xN11WSckkmA== + +elliptic@^6.5.3: + version "6.5.3" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6" + integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw== + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + +emittery@^0.7.1: + version "0.7.2" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82" + integrity sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ== + +emoji-regex@^7.0.1: + version "7.0.3" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +encodeurl@~1.0.1, encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + +end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +engine.io-client@~3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36" + integrity sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw== + dependencies: + component-emitter "1.2.1" + component-inherit "0.0.3" + debug "~3.1.0" + engine.io-parser "~2.1.1" + has-cors "1.1.0" + indexof "0.0.1" + parseqs "0.0.5" + parseuri "0.0.5" + ws "~3.3.1" + xmlhttprequest-ssl "~1.5.4" + yeast "0.1.2" + +engine.io-client@~3.4.0: + version "3.4.4" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.4.4.tgz#77d8003f502b0782dd792b073a4d2cf7ca5ab967" + integrity sha512-iU4CRr38Fecj8HoZEnFtm2EiKGbYZcPn3cHxqNGl/tmdWRf60KhK+9vE0JeSjgnlS/0oynEfLgKbT9ALpim0sQ== + dependencies: + component-emitter "~1.3.0" + component-inherit "0.0.3" + debug "~3.1.0" + engine.io-parser "~2.2.0" + has-cors "1.1.0" + indexof "0.0.1" + parseqs "0.0.6" + parseuri "0.0.6" + ws "~6.1.0" + xmlhttprequest-ssl "~1.5.4" + yeast "0.1.2" + +engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.3.tgz#757ab970fbf2dfb32c7b74b033216d5739ef79a6" + integrity sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA== + dependencies: + after "0.8.2" + arraybuffer.slice "~0.0.7" + base64-arraybuffer "0.1.5" + blob "0.0.5" + has-binary2 "~1.0.2" + +engine.io-parser@~2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.2.1.tgz#57ce5611d9370ee94f99641b589f94c97e4f5da7" + integrity sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg== + dependencies: + after "0.8.2" + arraybuffer.slice "~0.0.7" + base64-arraybuffer "0.1.4" + blob "0.0.5" + has-binary2 "~1.0.2" + +engine.io@~3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.2.1.tgz#b60281c35484a70ee0351ea0ebff83ec8c9522a2" + integrity sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w== + dependencies: + accepts "~1.3.4" + base64id "1.0.0" + cookie "0.3.1" + debug "~3.1.0" + engine.io-parser "~2.1.0" + ws "~3.3.1" + +enquirer@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" + integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== + dependencies: + ansi-colors "^4.1.1" + +error-ex@^1.2.0, error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +error@^7.0.0: + version "7.2.1" + resolved "https://registry.yarnpkg.com/error/-/error-7.2.1.tgz#eab21a4689b5f684fc83da84a0e390de82d94894" + integrity sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA== + dependencies: + string-template "~0.2.1" + +es-abstract@^1.17.4, es-abstract@^1.17.5: + version "1.17.7" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.7.tgz#a4de61b2f66989fc7421676c1cb9787573ace54c" + integrity sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g== + dependencies: + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.2.2" + is-regex "^1.1.1" + object-inspect "^1.8.0" + object-keys "^1.1.1" + object.assign "^4.1.1" + string.prototype.trimend "^1.0.1" + string.prototype.trimstart "^1.0.1" + +es-abstract@^1.18.0-next.1: + version "1.18.0-next.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.1.tgz#6e3a0a4bda717e5023ab3b8e90bec36108d22c68" + integrity sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA== + dependencies: + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.2.2" + is-negative-zero "^2.0.0" + is-regex "^1.1.1" + object-inspect "^1.8.0" + object-keys "^1.1.1" + object.assign "^4.1.1" + string.prototype.trimend "^1.0.1" + string.prototype.trimstart "^1.0.1" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + +es5-ext@^0.10.35, es5-ext@^0.10.45, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46: + version "0.10.53" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1" + integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q== + dependencies: + es6-iterator "~2.0.3" + es6-symbol "~3.1.3" + next-tick "~1.0.0" + +es6-iterator@^2.0.1, es6-iterator@^2.0.3, es6-iterator@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-symbol@^3.1.1, es6-symbol@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" + integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== + dependencies: + d "^1.0.1" + ext "^1.1.2" + +es6-weak-map@^2.0.1, es6-weak-map@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.3.tgz#b6da1f16cc2cc0d9be43e6bdbfc5e7dfcdf31d53" + integrity sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA== + dependencies: + d "1" + es5-ext "^0.10.46" + es6-iterator "^2.0.3" + es6-symbol "^3.1.1" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escodegen@^1.14.1: + version "1.14.3" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" + integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== + dependencies: + esprima "^4.0.1" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +eslint-plugin-jest@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.1.0.tgz#6708037d7602e5288ce877fd0103f329dc978361" + integrity sha512-827YJ+E8B9PvXu/0eiVSNFfxxndbKv+qE/3GSMhdorCaeaOehtqHGX2YDW9B85TEOre9n/zscledkFW/KbnyGg== + dependencies: + "@typescript-eslint/experimental-utils" "^4.0.1" + +eslint-scope@^5.0.0, eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-utils@^2.0.0, eslint-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" + integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== + +eslint@^7.12.1: + version "7.12.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.12.1.tgz#bd9a81fa67a6cfd51656cdb88812ce49ccec5801" + integrity sha512-HlMTEdr/LicJfN08LB3nM1rRYliDXOmfoO4vj39xN6BLpFzF00hbwBoqHk8UcJ2M/3nlARZWy/mslvGEuZFvsg== + dependencies: + "@babel/code-frame" "^7.0.0" + "@eslint/eslintrc" "^0.2.1" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.0.1" + doctrine "^3.0.0" + enquirer "^2.3.5" + eslint-scope "^5.1.1" + eslint-utils "^2.1.0" + eslint-visitor-keys "^2.0.0" + espree "^7.3.0" + esquery "^1.2.0" + esutils "^2.0.2" + file-entry-cache "^5.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.0.0" + globals "^12.1.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash "^4.17.19" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + progress "^2.0.0" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" + table "^5.2.3" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^7.3.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.0.tgz#dc30437cf67947cf576121ebd780f15eeac72348" + integrity sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw== + dependencies: + acorn "^7.4.0" + acorn-jsx "^5.2.0" + eslint-visitor-keys "^1.3.0" + +esprima@^4.0.0, esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57" + integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse-fb@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/estraverse-fb/-/estraverse-fb-1.3.2.tgz#d323a4cb5e5ac331cea033413a9253e1643e07c4" + integrity sha1-0yOky15awzHOoDNBOpJT4WQ+B8Q= + +estraverse@^4.1.1, estraverse@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" + integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@1.8.1, etag@^1.8.1, etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + +event-emitter@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + integrity sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk= + dependencies: + d "1" + es5-ext "~0.10.14" + +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +events@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379" + integrity sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg== + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +exec-sh@^0.3.2: + version "0.3.4" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5" + integrity sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A== + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +execa@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" + integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + human-signals "^1.1.1" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.0" + onetime "^5.1.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + +expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +expand-tilde@^2.0.0, expand-tilde@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" + integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI= + dependencies: + homedir-polyfill "^1.0.1" + +expect@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/expect/-/expect-26.6.2.tgz#c6b996bf26bf3fe18b67b2d0f51fc981ba934417" + integrity sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA== + dependencies: + "@jest/types" "^26.6.2" + ansi-styles "^4.0.0" + jest-get-type "^26.3.0" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-regex-util "^26.0.0" + +ext@^1.1.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244" + integrity sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A== + dependencies: + type "^2.0.0" + +extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + +extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + +extend@^3.0.0, extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + 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.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + +falafel@^2.0.0: + version "2.2.4" + resolved "https://registry.yarnpkg.com/falafel/-/falafel-2.2.4.tgz#b5d86c060c2412a43166243cb1bce44d1abd2819" + integrity sha512-0HXjo8XASWRmsS0X1EkhwEMZaD3Qvp7FfURwjLKjG1ghfRm/MGZl2r4cWUTv41KdNghTw4OUMmVtdGQp3+H+uQ== + dependencies: + acorn "^7.1.1" + foreach "^2.0.5" + isarray "^2.0.1" + object-keys "^1.0.6" + +fancy-log@^1.1.0, fancy-log@^1.3.2, fancy-log@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.3.tgz#dbc19154f558690150a23953a0adbd035be45fc7" + integrity sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw== + dependencies: + ansi-gray "^0.1.1" + color-support "^1.1.3" + parse-node-version "^1.0.0" + time-stamp "^1.0.0" + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.1.1: + version "3.2.4" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3" + integrity sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.0" + merge2 "^1.3.0" + micromatch "^4.0.2" + picomatch "^2.2.1" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz#e6a754cc8f15e58987aa9cbd27af66fd6f4e5af9" + integrity sha1-5qdUzI8V5YmHqpy9J69m/W9OWvk= + +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + +fast-safe-stringify@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743" + integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA== + +fastq@^1.6.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.9.0.tgz#e16a72f338eaca48e91b5c23593bcc2ef66b7947" + integrity sha512-i7FVWL8HhVY+CTkwFxkN2mk3h+787ixS5S63eb78diVRc1MCssarHq3W5cj0av7YDSwmaV928RNag+U1etRQ7w== + dependencies: + reusify "^1.0.4" + +faye-websocket@~0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" + integrity sha1-TkkvjQTftviQA1B/btvy1QHnxvQ= + dependencies: + websocket-driver ">=0.5.1" + +fb-watchman@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== + dependencies: + bser "2.1.1" + +file-entry-cache@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" + integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== + dependencies: + flat-cache "^2.0.1" + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" + integrity sha1-zgtoVbRYU+eRsvzGgARtiCU91/U= + dependencies: + debug "2.6.9" + encodeurl "~1.0.1" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.2" + statuses "~1.3.1" + unpipe "~1.0.0" + +finalhandler@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +find-cache-dir@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" + integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== + dependencies: + commondir "^1.0.1" + make-dir "^2.0.0" + pkg-dir "^3.0.0" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +findup-sync@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" + integrity sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw= + dependencies: + detect-file "^1.0.0" + is-glob "^3.1.0" + micromatch "^3.0.4" + resolve-dir "^1.0.1" + +findup-sync@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1" + integrity sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg== + dependencies: + detect-file "^1.0.0" + is-glob "^4.0.0" + micromatch "^3.0.4" + resolve-dir "^1.0.1" + +fined@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fined/-/fined-1.2.0.tgz#d00beccf1aa2b475d16d423b0238b713a2c4a37b" + integrity sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng== + dependencies: + expand-tilde "^2.0.2" + is-plain-object "^2.0.3" + object.defaults "^1.1.0" + object.pick "^1.2.0" + parse-filepath "^1.0.1" + +flagged-respawn@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-1.0.1.tgz#e7de6f1279ddd9ca9aac8a5971d618606b3aab41" + integrity sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q== + +flat-cache@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" + integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== + dependencies: + flatted "^2.0.0" + rimraf "2.6.3" + write "1.0.3" + +flatted@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" + integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== + +flow-parser@^0.*: + version "0.137.0" + resolved "https://registry.yarnpkg.com/flow-parser/-/flow-parser-0.137.0.tgz#8c05612ff9344648d8bcdeaa4c58d131e875d842" + integrity sha512-i3KXJZ8lhlQI0n+BoZzIeH/rv+fNvAiu1i9/s64MklBV+HuhFbycUML7367J2eng0gapLnwvYPFNaPZys8POsA== + +flush-write-stream@^1.0.2: + version "1.1.1" + resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" + integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== + dependencies: + inherits "^2.0.3" + readable-stream "^2.3.6" + +follow-redirects@1.5.10: + version "1.5.10" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" + integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== + dependencies: + debug "=3.1.0" + +follow-redirects@^1.0.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db" + integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA== + +for-in@^1.0.1, for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + +for-own@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b" + integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs= + dependencies: + for-in "^1.0.1" + +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +fork-stream@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/fork-stream/-/fork-stream-0.0.4.tgz#db849fce77f6708a5f8f386ae533a0907b54ae70" + integrity sha1-24Sfznf2cIpfjzhq5TOgkHtUrnA= + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + +fresh@0.5.2, fresh@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + +fs-extra@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-3.0.1.tgz#3794f378c58b342ea7dbbb23095109c4b3b62291" + integrity sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE= + dependencies: + graceful-fs "^4.1.2" + jsonfile "^3.0.0" + universalify "^0.1.0" + +fs-mkdirp-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz#0b7815fc3201c6a69e14db98ce098c16935259eb" + integrity sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes= + dependencies: + graceful-fs "^4.1.11" + through2 "^2.0.3" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@^1.2.7: + version "1.2.13" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" + integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw== + dependencies: + bindings "^1.5.0" + nan "^2.12.1" + +fsevents@^2.1.2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.2.0.tgz#4150396a427ecb5baa747725b70270a72b17bc17" + integrity sha512-pKnaUh2TNvk+/egJdBw1h46LwyLx8BzEq+MGCf/RMCVfEHHsGOCWG00dqk91kUPPArIIwMBg9T/virxwzP03cA== + +fsevents@~2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" + integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== + +fstream@^1.0.0, fstream@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" + integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +gaze@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a" + integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g== + dependencies: + globule "^1.0.0" + +gensync@^1.0.0-beta.1: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-assigned-identifiers@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz#6dbf411de648cbaf8d9169ebb0d2d576191e2ff1" + integrity sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ== + +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== + +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.0.1.tgz#94a9768fcbdd0595a1c9273aacf4c89d075631be" + integrity sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= + +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + +get-stream@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + +get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + +get-value@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-3.0.1.tgz#5efd2a157f1d6a516d7524e124ac52d0a39ef5a8" + integrity sha512-mKZj9JLQrwMBtj5wxi6MH8Z5eSKaERpAwjg43dPtlGI1ZVEgH/qC7T8/6R2OBSUA+zzHBZgICsVJaEIV2tKTDA== + dependencies: + isobject "^3.0.1" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + +glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@~5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" + integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== + dependencies: + is-glob "^4.0.1" + +glob-stream@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-6.1.0.tgz#7045c99413b3eb94888d83ab46d0b404cc7bdde4" + integrity sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ= + dependencies: + extend "^3.0.0" + glob "^7.1.1" + glob-parent "^3.1.0" + is-negated-glob "^1.0.0" + ordered-read-streams "^1.0.0" + pumpify "^1.3.5" + readable-stream "^2.1.5" + remove-trailing-separator "^1.0.1" + to-absolute-glob "^2.0.0" + unique-stream "^2.0.2" + +glob-watcher@^5.0.3: + version "5.0.5" + resolved "https://registry.yarnpkg.com/glob-watcher/-/glob-watcher-5.0.5.tgz#aa6bce648332924d9a8489be41e3e5c52d4186dc" + integrity sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw== + dependencies: + anymatch "^2.0.0" + async-done "^1.2.0" + chokidar "^2.0.0" + is-negated-glob "^1.0.0" + just-debounce "^1.0.0" + normalize-path "^3.0.0" + object.defaults "^1.1.0" + +glob@^7.0.0, glob@^7.0.3, glob@^7.1.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@~7.1.1: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-modules@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea" + integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg== + dependencies: + global-prefix "^1.0.1" + is-windows "^1.0.1" + resolve-dir "^1.0.0" + +global-prefix@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe" + integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4= + dependencies: + expand-tilde "^2.0.2" + homedir-polyfill "^1.0.1" + ini "^1.3.4" + is-windows "^1.0.1" + which "^1.2.14" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^12.1.0: + version "12.4.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" + integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== + dependencies: + type-fest "^0.8.1" + +globby@^11.0.1: + version "11.0.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357" + integrity sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + +globule@^1.0.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/globule/-/globule-1.3.2.tgz#d8bdd9e9e4eef8f96e245999a5dee7eb5d8529c4" + integrity sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA== + dependencies: + glob "~7.1.1" + lodash "~4.17.10" + minimatch "~3.0.2" + +glogg@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.2.tgz#2d7dd702beda22eb3bffadf880696da6d846313f" + integrity sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA== + dependencies: + sparkles "^1.0.0" + +graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.4: + version "4.2.4" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" + integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== + +grasp-equery@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/grasp-equery/-/grasp-equery-0.4.0.tgz#5016329c1eecacfe3671cede7c9bc0fc99b10d7b" + integrity sha1-UBYynB7srP42cc7efJvA/JmxDXs= + dependencies: + flow-parser "^0.*" + grasp-syntax-javascript "^0.2.0" + prelude-ls "^1.1.2" + +grasp-squery@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/grasp-squery/-/grasp-squery-0.4.0.tgz#05593a7e836eba80a3465f9603f2c366aaf5397f" + integrity sha1-BVk6foNuuoCjRl+WA/LDZqr1OX8= + dependencies: + grasp-syntax-javascript "~0.2.0" + prelude-ls "~1.1.2" + +grasp-syntax-javascript@^0.2.0, grasp-syntax-javascript@~0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/grasp-syntax-javascript/-/grasp-syntax-javascript-0.2.2.tgz#660ffd8ffb1eb108f77447594ac37e72b2b3504c" + integrity sha1-Zg/9j/sesQj3dEdZSsN+crKzUEw= + dependencies: + prelude-ls "~1.1.2" + +grasp@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/grasp/-/grasp-0.6.0.tgz#7ecf1e26479cb4dec899b898a8afdf8b7d83fc53" + integrity sha1-fs8eJkectN7ImbiYqK/fi32D/FM= + dependencies: + async "^1.5.0" + cli-color "^1.1.0" + flow-parser "^0.*" + grasp-equery "^0.4.0" + grasp-squery "^0.4.0" + grasp-syntax-javascript "^0.2.0" + levn "^0.3.0" + minimatch "^3.0.3" + optionator "^0.8.0" + prelude-ls "^1.1.2" + slash "^1.0.0" + +group-array@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/group-array/-/group-array-1.0.0.tgz#e2e8d8890e5b46f72eb49b71e8af675173a9d0f7" + integrity sha512-PJresALe5TUzSIcdWKLdAKcdUDxv8du2EGueShgAL2xknbcTo5Bk1xbNaNhxpWxxAx/SV7N+5S0UyK7XV0+QhA== + dependencies: + arr-flatten "^1.1.0" + for-own "^1.0.0" + get-value "^3.0.1" + kind-of "^6.0.2" + split-string "^6.1.0" + union-value "^2.0.1" + +growly@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= + +gulp-autoprefixer@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/gulp-autoprefixer/-/gulp-autoprefixer-7.0.1.tgz#3c0dc26afc802d317e7560a7f760a0399049075a" + integrity sha512-QJGEmHw+bEt7FSqvmbAUTxbCuNLJYx4sz3ox9WouYqT/7j5FH5CQ8ZnpL1M7H5npX1bUJa7lUVY1w20jXxhOxg== + dependencies: + autoprefixer "^9.6.1" + fancy-log "^1.3.2" + plugin-error "^1.0.1" + postcss "^7.0.17" + through2 "^3.0.1" + vinyl-sourcemaps-apply "^0.2.1" + +gulp-babel@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/gulp-babel/-/gulp-babel-8.0.0.tgz#e0da96f4f2ec4a88dd3a3030f476e38ab2126d87" + integrity sha512-oomaIqDXxFkg7lbpBou/gnUkX51/Y/M2ZfSjL2hdqXTAlSWZcgZtd2o0cOH0r/eE8LWD0+Q/PsLsr2DKOoqToQ== + dependencies: + plugin-error "^1.0.1" + replace-ext "^1.0.0" + through2 "^2.0.0" + vinyl-sourcemaps-apply "^0.2.0" + +gulp-clean-css@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/gulp-clean-css/-/gulp-clean-css-4.3.0.tgz#5b1e73f2fca46703eb636014cdd4553cea65146d" + integrity sha512-mGyeT3qqFXTy61j0zOIciS4MkYziF2U594t2Vs9rUnpkEHqfu6aDITMp8xOvZcvdX61Uz3y1mVERRYmjzQF5fg== + dependencies: + clean-css "4.2.3" + plugin-error "1.0.1" + through2 "3.0.1" + vinyl-sourcemaps-apply "0.2.1" + +gulp-cli@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/gulp-cli/-/gulp-cli-2.3.0.tgz#ec0d380e29e52aa45e47977f0d32e18fd161122f" + integrity sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A== + dependencies: + ansi-colors "^1.0.1" + archy "^1.0.0" + array-sort "^1.0.0" + color-support "^1.1.3" + concat-stream "^1.6.0" + copy-props "^2.0.1" + fancy-log "^1.3.2" + gulplog "^1.0.0" + interpret "^1.4.0" + isobject "^3.0.1" + liftoff "^3.1.0" + matchdep "^2.0.0" + mute-stdout "^1.0.0" + pretty-hrtime "^1.0.0" + replace-homedir "^1.0.0" + semver-greatest-satisfied-range "^1.1.0" + v8flags "^3.2.0" + yargs "^7.1.0" + +gulp-concat@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/gulp-concat/-/gulp-concat-2.6.1.tgz#633d16c95d88504628ad02665663cee5a4793353" + integrity sha1-Yz0WyV2IUEYorQJmVmPO5aR5M1M= + dependencies: + concat-with-sourcemaps "^1.0.0" + through2 "^2.0.0" + vinyl "^2.0.0" + +gulp-connect@^5.0.0: + version "5.7.0" + resolved "https://registry.yarnpkg.com/gulp-connect/-/gulp-connect-5.7.0.tgz#7e925f5e4c34ebfedf9f318576966e8fe8840d5a" + integrity sha512-8tRcC6wgXMLakpPw9M7GRJIhxkYdgZsXwn7n56BA2bQYGLR9NOPhMzx7js+qYDy6vhNkbApGKURjAw1FjY4pNA== + dependencies: + ansi-colors "^2.0.5" + connect "^3.6.6" + connect-livereload "^0.6.0" + fancy-log "^1.3.2" + map-stream "^0.0.7" + send "^0.16.2" + serve-index "^1.9.1" + serve-static "^1.13.2" + tiny-lr "^1.1.1" + +gulp-css-base64@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/gulp-css-base64/-/gulp-css-base64-2.0.0.tgz#a3984789ccda2079b075ee2b323213945812a8e2" + integrity sha512-8ZtWdWEzBCL4Pa/kNCNssXRlXzQmz9fmrJRf2q5fBwg5OzBB1DTs7hXvAZMQMCoKgQ+HLEylw97OIEXALHdtGw== + dependencies: + async "^1.5.0" + buffers "^0.1.1" + chalk "^1.1.1" + fancy-log "^1.3.3" + mime "^1.3.4" + plugin-error "^1.0.1" + request "^2.67.0" + through2 "^2.0.0" + vinyl "^2.2.0" + +gulp-html-to-js@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/gulp-html-to-js/-/gulp-html-to-js-0.0.7.tgz#c59ebde458ec4be55d84cc17c8a4061b417b9c5a" + integrity sha512-P4iQ9roXfI15M6MXNo2cJvOEWI6VdIZZTeLmqtqMt0JhXihh2vO0EtuCvzFID+lTG3HtG0jbw1vPTFQzbCxUFw== + +gulp-htmlmin@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/gulp-htmlmin/-/gulp-htmlmin-5.0.1.tgz#90fc5e8ad0425a9e86d5d521427184e7276365e7" + integrity sha512-ASlyDPZOSKjHYUifYV0rf9JPDflN9IRIb8lw2vRqtYMC4ljU3zAmnnaVXwFQ3H+CfXxZSUesZ2x7jrnPJu93jA== + dependencies: + html-minifier "^3.5.20" + plugin-error "^1.0.1" + through2 "^2.0.3" + +gulp-if@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/gulp-if/-/gulp-if-3.0.0.tgz#6c3e7edc8bafadc34f2ebecb314bf43324ba1e40" + integrity sha512-fCUEngzNiEZEK2YuPm+sdMpO6ukb8+/qzbGfJBXyNOXz85bCG7yBI+pPSl+N90d7gnLvMsarthsAImx0qy7BAw== + dependencies: + gulp-match "^1.1.0" + ternary-stream "^3.0.0" + through2 "^3.0.1" + +gulp-inject@^5.0.5: + version "5.0.5" + resolved "https://registry.yarnpkg.com/gulp-inject/-/gulp-inject-5.0.5.tgz#c23df9cbf331447b6e13a1498cc51b63a7ceef67" + integrity sha512-5bGMjqleXUHPu4CI1pnVzHtwyMy+Zt8EMo1RFwNsOpidPxwjFwyLgmsRZWGMMI8UenJMJRjURqwznfFmqb5wgw== + dependencies: + ansi-colors "^4.1.1" + arrify "^2.0.1" + escape-string-regexp "^2.0.0" + fancy-log "^1.3.3" + group-array "^1.0.0" + plugin-error "^1.0.1" + stream-to-array "^2.3.0" + through2 "^3.0.1" + +gulp-match@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/gulp-match/-/gulp-match-1.1.0.tgz#552b7080fc006ee752c90563f9fec9d61aafdf4f" + integrity sha512-DlyVxa1Gj24DitY2OjEsS+X6tDpretuxD6wTfhXE/Rw2hweqc1f6D/XtsJmoiCwLWfXgR87W9ozEityPCVzGtQ== + dependencies: + minimatch "^3.0.3" + +gulp-sass@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/gulp-sass/-/gulp-sass-4.1.0.tgz#486d7443c32d42bf31a6b1573ebbdaa361de7427" + integrity sha512-xIiwp9nkBLcJDpmYHbEHdoWZv+j+WtYaKD6Zil/67F3nrAaZtWYN5mDwerdo7EvcdBenSAj7Xb2hx2DqURLGdA== + dependencies: + chalk "^2.3.0" + lodash "^4.17.11" + node-sass "^4.8.3" + plugin-error "^1.0.1" + replace-ext "^1.0.0" + strip-ansi "^4.0.0" + through2 "^2.0.0" + vinyl-sourcemaps-apply "^0.2.0" + +gulp-streamify@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/gulp-streamify/-/gulp-streamify-1.0.2.tgz#00d6b3814d486c088f78738ed0766abc16389e4d" + integrity sha1-ANazgU1IbAiPeHOO0HZqvBY4nk0= + dependencies: + plexer "1.0.1" + +gulp-tap@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/gulp-tap/-/gulp-tap-2.0.0.tgz#6f66b79870dcbfc364cf4ebe0735b6008473200f" + integrity sha512-U5/v1bTozx672QHzrvzPe6fPl2io7Wqyrx2y30AG53eMU/idH4BrY/b2yikOkdyhjDqGgPoMUMnpBg9e9LK8Nw== + dependencies: + through2 "^3.0.1" + +gulp-uglify-es@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/gulp-uglify-es/-/gulp-uglify-es-2.0.0.tgz#0a48d9f352393397e78cf2be44bf0fb66a353031" + integrity sha512-00KkawzjWdjPo1YfD1FXKijVxZkyr6YSwJ2cJQgD1fNKFZCFPNjGc5sTyzyW8tZns8FmZafgHMrg7LUDNvIQ5A== + dependencies: + o-stream "^0.2.2" + plugin-error "^1.0.1" + terser "^4.3.9" + vinyl "^2.2.0" + vinyl-sourcemaps-apply "^0.2.1" + +gulp-using@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/gulp-using/-/gulp-using-0.1.1.tgz#6f5a6827fdf4c364a31cbdecd425202aa5a268e7" + integrity sha1-b1poJ/30w2SjHL3s1CUgKqWiaOc= + dependencies: + chalk "~0.4.0" + map-stream "~0.1.0" + pretty-bytes "^3.0.1" + +gulp-util@^3.0.8: + version "3.0.8" + resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f" + integrity sha1-AFTh50RQLifATBh8PsxQXdVLu08= + dependencies: + array-differ "^1.0.0" + array-uniq "^1.0.2" + beeper "^1.0.0" + chalk "^1.0.0" + dateformat "^2.0.0" + fancy-log "^1.1.0" + gulplog "^1.0.0" + has-gulplog "^0.1.0" + lodash._reescape "^3.0.0" + lodash._reevaluate "^3.0.0" + lodash._reinterpolate "^3.0.0" + lodash.template "^3.0.0" + minimist "^1.1.0" + multipipe "^0.1.2" + object-assign "^3.0.0" + replace-ext "0.0.1" + through2 "^2.0.0" + vinyl "^0.5.0" + +gulp@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/gulp/-/gulp-4.0.2.tgz#543651070fd0f6ab0a0650c6a3e6ff5a7cb09caa" + integrity sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA== + dependencies: + glob-watcher "^5.0.3" + gulp-cli "^2.2.0" + undertaker "^1.2.1" + vinyl-fs "^3.0.0" + +gulplog@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/gulplog/-/gulplog-1.0.0.tgz#e28c4d45d05ecbbed818363ce8f9c5926229ffe5" + integrity sha1-4oxNRdBey77YGDY86PnFkmIp/+U= + dependencies: + glogg "^1.0.0" + +har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~5.1.3: + version "5.1.5" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== + dependencies: + ajv "^6.12.3" + har-schema "^2.0.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + dependencies: + ansi-regex "^2.0.0" + +has-binary2@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" + integrity sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw== + dependencies: + isarray "2.0.1" + +has-color@~0.1.0: + version "0.1.7" + resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f" + integrity sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8= + +has-cors@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk= + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-gulplog@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce" + integrity sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4= + dependencies: + sparkles "^1.0.0" + +has-symbols@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" + integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + +has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + +has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + +has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + +has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + +has@^1.0.0, has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +he@1.2.x: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +homedir-polyfill@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8" + integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA== + dependencies: + parse-passwd "^1.0.0" + +hosted-git-info@^2.1.4: + version "2.8.8" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" + integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== + +html-encoding-sniffer@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" + integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== + dependencies: + whatwg-encoding "^1.0.5" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +html-minifier@^3.5.20: + version "3.5.21" + resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.21.tgz#d0040e054730e354db008463593194015212d20c" + integrity sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA== + dependencies: + camel-case "3.0.x" + clean-css "4.2.x" + commander "2.17.x" + he "1.2.x" + param-case "2.1.x" + relateurl "0.2.x" + uglify-js "3.4.x" + +htmlescape@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/htmlescape/-/htmlescape-1.1.1.tgz#3a03edc2214bca3b66424a3e7959349509cb0351" + integrity sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E= + +http-errors@1.7.3, http-errors@~1.7.2: + version "1.7.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" + integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.1.1" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.0" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-parser-js@>=0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.2.tgz#da2e31d237b393aae72ace43882dd7e270a8ff77" + integrity sha512-opCO9ASqg5Wy2FNo7A0sxy71yGbbkJJXLdgMK04Tcypw9jr2MgWbyubb0+WdmDmGnFflO7fRbqbaihh/ENDlRQ== + +http-proxy@^1.18.1: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= + +human-signals@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" + integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ieee754@^1.1.4: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +ignore@^5.1.4: + version "5.1.8" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" + integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== + +immutable@^3: + version "3.8.2" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.2.tgz#c2439951455bb39913daf281376f1530e104adf3" + integrity sha1-wkOZUUVbs5kT2vKBN28VMOEErfM= + +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.2.tgz#fc129c160c5d68235507f4331a6baad186bdbc3e" + integrity sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-local@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.2.tgz#a8cfd0431d1de4a2199703d003e3e62364fa6db6" + integrity sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + +in-publish@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.1.tgz#948b1a535c8030561cea522f73f78f4be357e00c" + integrity sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ== + +indent-string@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= + dependencies: + repeating "^2.0.0" + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + +ini@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== + +inline-source-map@~0.6.0: + version "0.6.2" + resolved "https://registry.yarnpkg.com/inline-source-map/-/inline-source-map-0.6.2.tgz#f9393471c18a79d1724f863fa38b586370ade2a5" + integrity sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU= + dependencies: + source-map "~0.5.3" + +insert-module-globals@^7.2.1: + version "7.2.1" + resolved "https://registry.yarnpkg.com/insert-module-globals/-/insert-module-globals-7.2.1.tgz#d5e33185181a4e1f33b15f7bf100ee91890d5cb3" + integrity sha512-ufS5Qq9RZN+Bu899eA9QCAYThY+gGW7oRkmb0vC93Vlyu/CFGcH0OYPEjVkDXA5FEbTt1+VWzdoOD3Ny9N+8tg== + dependencies: + JSONStream "^1.0.3" + acorn-node "^1.5.2" + combine-source-map "^0.8.0" + concat-stream "^1.6.1" + is-buffer "^1.1.0" + path-is-absolute "^1.0.1" + process "~0.11.0" + through2 "^2.0.0" + undeclared-identifiers "^1.1.2" + xtend "^4.0.0" + +interpret@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= + +ip-regex@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= + +is-absolute@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-1.0.0.tgz#395e1ae84b11f26ad1795e73c17378e48a301576" + integrity sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA== + dependencies: + is-relative "^1.0.0" + is-windows "^1.0.1" + +is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + +is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + +is-arguments@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.0.4.tgz#3faf966c7cba0ff437fb31f6250082fcf0448cf3" + integrity sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= + dependencies: + binary-extensions "^1.0.0" + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-buffer@^1.1.0, is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + +is-buffer@^2.0.2: + version "2.0.5" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" + integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== + +is-callable@^1.1.4, is-callable@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.2.tgz#c7c6715cd22d4ddb48d3e19970223aceabb080d9" + integrity sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA== + +is-ci@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== + dependencies: + ci-info "^2.0.0" + +is-core-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.0.0.tgz#58531b70aed1db7c0e8d4eb1a0a2d1ddd64bd12d" + integrity sha512-jq1AH6C8MuteOoBPwkxHafmByhL9j5q4OaPGdbuD+ZtQJVzH+i6E3BJDQcBA09k57i2Hh2yQbEG8yObZ0jdlWw== + dependencies: + has "^1.0.3" + +is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + +is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + +is-date-object@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" + integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== + +is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + +is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + +is-docker@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.1.1.tgz#4125a88e44e450d384e09047ede71adc2d144156" + integrity sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw== + +is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + +is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + +is-extglob@^2.1.0, is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + +is-finite@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" + integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-generator-function@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522" + integrity sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw== + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= + dependencies: + is-extglob "^2.1.0" + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + dependencies: + is-extglob "^2.1.1" + +is-negated-glob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-negated-glob/-/is-negated-glob-1.0.0.tgz#6910bca5da8c95e784b5751b976cf5a10fee36d2" + integrity sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI= + +is-negative-zero@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.0.tgz#9553b121b0fac28869da9ed459e20c7543788461" + integrity sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE= + +is-number-like@^1.0.3: + version "1.0.8" + resolved "https://registry.yarnpkg.com/is-number-like/-/is-number-like-1.0.8.tgz#2e129620b50891042e44e9bbbb30593e75cfbbe3" + integrity sha512-6rZi3ezCyFcn5L71ywzz2bS5b2Igl1En3eTlZlvKjpz1n3IZLAYMbKYAIQgFmEu0GENg92ziU/faEOA/aixjbA== + dependencies: + lodash.isfinite "^3.3.2" + +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + +is-number@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-path-cwd@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" + integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== + +is-path-inside@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.2.tgz#f5220fc82a3e233757291dddc9c5877f2a1f3017" + integrity sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg== + +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-potential-custom-element-name@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz#0c52e54bcca391bb2c494b21e8626d7336c6e397" + integrity sha1-DFLlS8yjkbssSUsh6GJtczbG45c= + +is-promise@^2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" + integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== + +is-regex@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.1.tgz#c6f98aacc546f6cec5468a07b7b153ab564a57b9" + integrity sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg== + dependencies: + has-symbols "^1.0.1" + +is-relative@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d" + integrity sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA== + dependencies: + is-unc-path "^1.0.0" + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + +is-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" + integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== + +is-symbol@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" + integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== + dependencies: + has-symbols "^1.0.1" + +is-typed-array@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.3.tgz#a4ff5a5e672e1a55f99c7f54e59597af5c1df04d" + integrity sha512-BSYUBOK/HJibQ30wWkWold5txYwMUXQct9YHAQJr8fSwvZoiglcqB0pd7vEN23+Tsi9IUEjztdOSzl4qLVYGTQ== + dependencies: + available-typed-arrays "^1.0.0" + es-abstract "^1.17.4" + foreach "^2.0.5" + has-symbols "^1.0.1" + +is-typedarray@^1.0.0, is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-unc-path@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-1.0.0.tgz#d731e8898ed090a12c352ad2eaed5095ad322c9d" + integrity sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ== + dependencies: + unc-path-regex "^0.1.2" + +is-utf8@^0.2.0, is-utf8@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= + +is-valid-glob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-1.0.0.tgz#29bf3eff701be2d4d315dbacc39bc39fe8f601aa" + integrity sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao= + +is-windows@^1.0.1, is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= + +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + +isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +isarray@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" + integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4= + +isarray@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + +isstream@^0.1.2, isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + +istanbul-lib-coverage@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" + integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== + +istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" + integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== + dependencies: + "@babel/core" "^7.7.5" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.0.0" + semver "^6.3.0" + +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz#75743ce6d96bb86dc7ee4352cf6366a23f0b1ad9" + integrity sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" + integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.6.2.tgz#f6198479e1cc66f22f9ae1e22acaa0b429c042d0" + integrity sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ== + dependencies: + "@jest/types" "^26.6.2" + execa "^4.0.0" + throat "^5.0.0" + +jest-cli@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.6.3.tgz#43117cfef24bc4cd691a174a8796a532e135e92a" + integrity sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg== + dependencies: + "@jest/core" "^26.6.3" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.4" + import-local "^3.0.2" + is-ci "^2.0.0" + jest-config "^26.6.3" + jest-util "^26.6.2" + jest-validate "^26.6.2" + prompts "^2.0.1" + yargs "^15.4.1" + +jest-config@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.6.3.tgz#64f41444eef9eb03dc51d5c53b75c8c71f645349" + integrity sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg== + dependencies: + "@babel/core" "^7.1.0" + "@jest/test-sequencer" "^26.6.3" + "@jest/types" "^26.6.2" + babel-jest "^26.6.3" + chalk "^4.0.0" + deepmerge "^4.2.2" + glob "^7.1.1" + graceful-fs "^4.2.4" + jest-environment-jsdom "^26.6.2" + jest-environment-node "^26.6.2" + jest-get-type "^26.3.0" + jest-jasmine2 "^26.6.3" + jest-regex-util "^26.0.0" + jest-resolve "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" + micromatch "^4.0.2" + pretty-format "^26.6.2" + +jest-diff@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" + integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== + dependencies: + chalk "^4.0.0" + diff-sequences "^26.6.2" + jest-get-type "^26.3.0" + pretty-format "^26.6.2" + +jest-docblock@^26.0.0: + version "26.0.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5" + integrity sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w== + dependencies: + detect-newline "^3.0.0" + +jest-each@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.6.2.tgz#02526438a77a67401c8a6382dfe5999952c167cb" + integrity sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A== + dependencies: + "@jest/types" "^26.6.2" + chalk "^4.0.0" + jest-get-type "^26.3.0" + jest-util "^26.6.2" + pretty-format "^26.6.2" + +jest-environment-jsdom@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz#78d09fe9cf019a357009b9b7e1f101d23bd1da3e" + integrity sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q== + dependencies: + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" + jest-util "^26.6.2" + jsdom "^16.4.0" + +jest-environment-node@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.6.2.tgz#824e4c7fb4944646356f11ac75b229b0035f2b0c" + integrity sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag== + dependencies: + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" + jest-util "^26.6.2" + +jest-get-type@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" + integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== + +jest-haste-map@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa" + integrity sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w== + dependencies: + "@jest/types" "^26.6.2" + "@types/graceful-fs" "^4.1.2" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.4" + jest-regex-util "^26.0.0" + jest-serializer "^26.6.2" + jest-util "^26.6.2" + jest-worker "^26.6.2" + micromatch "^4.0.2" + sane "^4.0.3" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.1.2" + +jest-jasmine2@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz#adc3cf915deacb5212c93b9f3547cd12958f2edd" + integrity sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg== + dependencies: + "@babel/traverse" "^7.1.0" + "@jest/environment" "^26.6.2" + "@jest/source-map" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + expect "^26.6.2" + is-generator-fn "^2.0.0" + jest-each "^26.6.2" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-runtime "^26.6.3" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + pretty-format "^26.6.2" + throat "^5.0.0" + +jest-junit@^12.0.0: + version "12.0.0" + resolved "https://registry.yarnpkg.com/jest-junit/-/jest-junit-12.0.0.tgz#3ebd4a6a84b50c4ab18323a8f7d9cceb9d845df6" + integrity sha512-+8K35LlboWiPuCnXSyiid7rFdxNlpCWWM20WEYe6IZH6psfUWKZmSpSRQ5tk0C0cBeDsvsnIzcef5mYhyJsbug== + dependencies: + mkdirp "^1.0.4" + strip-ansi "^5.2.0" + uuid "^3.3.3" + xml "^1.0.1" + +jest-leak-detector@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz#7717cf118b92238f2eba65054c8a0c9c653a91af" + integrity sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg== + dependencies: + jest-get-type "^26.3.0" + pretty-format "^26.6.2" + +jest-matcher-utils@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz#8e6fd6e863c8b2d31ac6472eeb237bc595e53e7a" + integrity sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw== + dependencies: + chalk "^4.0.0" + jest-diff "^26.6.2" + jest-get-type "^26.3.0" + pretty-format "^26.6.2" + +jest-message-util@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.6.2.tgz#58173744ad6fc0506b5d21150b9be56ef001ca07" + integrity sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA== + dependencies: + "@babel/code-frame" "^7.0.0" + "@jest/types" "^26.6.2" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.4" + micromatch "^4.0.2" + pretty-format "^26.6.2" + slash "^3.0.0" + stack-utils "^2.0.2" + +jest-mock@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.6.2.tgz#d6cb712b041ed47fe0d9b6fc3474bc6543feb302" + integrity sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew== + dependencies: + "@jest/types" "^26.6.2" + "@types/node" "*" + +jest-pnp-resolver@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" + integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== + +jest-regex-util@^26.0.0: + version "26.0.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" + integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== + +jest-resolve-dependencies@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz#6680859ee5d22ee5dcd961fe4871f59f4c784fb6" + integrity sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg== + dependencies: + "@jest/types" "^26.6.2" + jest-regex-util "^26.0.0" + jest-snapshot "^26.6.2" + +jest-resolve@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.6.2.tgz#a3ab1517217f469b504f1b56603c5bb541fbb507" + integrity sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ== + dependencies: + "@jest/types" "^26.6.2" + chalk "^4.0.0" + graceful-fs "^4.2.4" + jest-pnp-resolver "^1.2.2" + jest-util "^26.6.2" + read-pkg-up "^7.0.1" + resolve "^1.18.1" + slash "^3.0.0" + +jest-runner@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.6.3.tgz#2d1fed3d46e10f233fd1dbd3bfaa3fe8924be159" + integrity sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ== + dependencies: + "@jest/console" "^26.6.2" + "@jest/environment" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.7.1" + exit "^0.1.2" + graceful-fs "^4.2.4" + jest-config "^26.6.3" + jest-docblock "^26.0.0" + jest-haste-map "^26.6.2" + jest-leak-detector "^26.6.2" + jest-message-util "^26.6.2" + jest-resolve "^26.6.2" + jest-runtime "^26.6.3" + jest-util "^26.6.2" + jest-worker "^26.6.2" + source-map-support "^0.5.6" + throat "^5.0.0" + +jest-runtime@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.6.3.tgz#4f64efbcfac398331b74b4b3c82d27d401b8fa2b" + integrity sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw== + dependencies: + "@jest/console" "^26.6.2" + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/globals" "^26.6.2" + "@jest/source-map" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/yargs" "^15.0.0" + chalk "^4.0.0" + cjs-module-lexer "^0.6.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.4" + jest-config "^26.6.3" + jest-haste-map "^26.6.2" + jest-message-util "^26.6.2" + jest-mock "^26.6.2" + jest-regex-util "^26.0.0" + jest-resolve "^26.6.2" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" + slash "^3.0.0" + strip-bom "^4.0.0" + yargs "^15.4.1" + +jest-serializer@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.6.2.tgz#d139aafd46957d3a448f3a6cdabe2919ba0742d1" + integrity sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g== + dependencies: + "@types/node" "*" + graceful-fs "^4.2.4" + +jest-snapshot@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.6.2.tgz#f3b0af1acb223316850bd14e1beea9837fb39c84" + integrity sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og== + dependencies: + "@babel/types" "^7.0.0" + "@jest/types" "^26.6.2" + "@types/babel__traverse" "^7.0.4" + "@types/prettier" "^2.0.0" + chalk "^4.0.0" + expect "^26.6.2" + graceful-fs "^4.2.4" + jest-diff "^26.6.2" + jest-get-type "^26.3.0" + jest-haste-map "^26.6.2" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-resolve "^26.6.2" + natural-compare "^1.4.0" + pretty-format "^26.6.2" + semver "^7.3.2" + +jest-util@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" + integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q== + dependencies: + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + graceful-fs "^4.2.4" + is-ci "^2.0.0" + micromatch "^4.0.2" + +jest-validate@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec" + integrity sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ== + dependencies: + "@jest/types" "^26.6.2" + camelcase "^6.0.0" + chalk "^4.0.0" + jest-get-type "^26.3.0" + leven "^3.1.0" + pretty-format "^26.6.2" + +jest-watcher@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.6.2.tgz#a5b683b8f9d68dbcb1d7dae32172d2cca0592975" + integrity sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ== + dependencies: + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + jest-util "^26.6.2" + string-length "^4.0.1" + +jest-worker@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" + integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^7.0.0" + +jest@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest/-/jest-26.6.3.tgz#40e8fdbe48f00dfa1f0ce8121ca74b88ac9148ef" + integrity sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q== + dependencies: + "@jest/core" "^26.6.3" + import-local "^3.0.2" + jest-cli "^26.6.3" + +js-base64@^2.1.8: + version "2.6.4" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.6.4.tgz#f4e686c5de1ea1f867dbcad3d46d969428df98c4" + integrity sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ== + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.0.tgz#a7a34170f26a21bb162424d8adacb4113a69e482" + integrity sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +jsdom@^16.4.0: + version "16.4.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.4.0.tgz#36005bde2d136f73eee1a830c6d45e55408edddb" + integrity sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w== + dependencies: + abab "^2.0.3" + acorn "^7.1.1" + acorn-globals "^6.0.0" + cssom "^0.4.4" + cssstyle "^2.2.0" + data-urls "^2.0.0" + decimal.js "^10.2.0" + domexception "^2.0.1" + escodegen "^1.14.1" + html-encoding-sniffer "^2.0.1" + is-potential-custom-element-name "^1.0.0" + nwsapi "^2.2.0" + parse5 "5.1.1" + request "^2.88.2" + request-promise-native "^1.0.8" + saxes "^5.0.0" + symbol-tree "^3.2.4" + tough-cookie "^3.0.1" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^2.0.0" + webidl-conversions "^6.1.0" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.0.0" + ws "^7.2.3" + xml-name-validator "^3.0.0" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + +json5@^2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" + integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== + dependencies: + minimist "^1.2.5" + +jsonfile@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66" + integrity sha1-pezG9l9T9mLEQVx2daAzHQmS7GY= + optionalDependencies: + graceful-fs "^4.1.6" + +jsonparse@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + +just-debounce@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.0.0.tgz#87fccfaeffc0b68cd19d55f6722943f929ea35ea" + integrity sha1-h/zPrv/AtozRnVX2cilD+SnqNeo= + +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + +kind-of@^5.0.0, kind-of@^5.0.2: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + +kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +labeled-stream-splicer@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz#42a41a16abcd46fd046306cf4f2c3576fffb1c21" + integrity sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw== + dependencies: + inherits "^2.0.1" + stream-splicer "^2.0.0" + +last-run@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/last-run/-/last-run-1.1.1.tgz#45b96942c17b1c79c772198259ba943bebf8ca5b" + integrity sha1-RblpQsF7HHnHchmCWbqUO+v4yls= + dependencies: + default-resolution "^2.0.0" + es6-weak-map "^2.0.1" + +lazystream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" + integrity sha1-9plf4PggOS9hOWvolGJAe7dxaOQ= + dependencies: + readable-stream "^2.0.5" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= + dependencies: + invert-kv "^1.0.0" + +lead@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lead/-/lead-1.0.0.tgz#6f14f99a37be3a9dd784f5495690e5903466ee42" + integrity sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI= + dependencies: + flush-write-stream "^1.0.2" + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +liftoff@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-3.1.0.tgz#c9ba6081f908670607ee79062d700df062c52ed3" + integrity sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog== + dependencies: + extend "^3.0.0" + findup-sync "^3.0.0" + fined "^1.0.1" + flagged-respawn "^1.0.0" + is-plain-object "^2.0.4" + object.map "^1.0.0" + rechoir "^0.6.2" + resolve "^1.1.7" + +limiter@^1.0.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/limiter/-/limiter-1.1.5.tgz#8f92a25b3b16c6131293a0cc834b4a838a2aa7c2" + integrity sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA== + +lines-and-columns@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" + integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= + +livereload-js@^2.3.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/livereload-js/-/livereload-js-2.4.0.tgz#447c31cf1ea9ab52fc20db615c5ddf678f78009c" + integrity sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw== + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +localtunnel@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/localtunnel/-/localtunnel-2.0.0.tgz#2ea71174fa80e34cce91b2a7ce416e6a57d9ff7c" + integrity sha512-g6E0aLgYYDvQDxIjIXkgJo2+pHj3sGg4Wz/XP3h2KtZnRsWPbOQY+hw1H8Z91jep998fkcVE9l+kghO+97vllg== + dependencies: + axios "0.19.0" + debug "4.1.1" + openurl "1.1.1" + yargs "13.3.0" + +locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lodash._basecopy@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + integrity sha1-jaDmqHbPNEwK2KVIghEd08XHyjY= + +lodash._basetostring@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz#d1861d877f824a52f669832dcaf3ee15566a07d5" + integrity sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U= + +lodash._basevalues@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz#5b775762802bde3d3297503e26300820fdf661b7" + integrity sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc= + +lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U= + +lodash._isiterateecall@^3.0.0: + version "3.0.9" + resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + integrity sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw= + +lodash._reescape@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reescape/-/lodash._reescape-3.0.0.tgz#2b1d6f5dfe07c8a355753e5f27fac7f1cde1616a" + integrity sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo= + +lodash._reevaluate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz#58bc74c40664953ae0b124d806996daca431e2ed" + integrity sha1-WLx0xAZklTrgsSTYBpltrKQx4u0= + +lodash._reinterpolate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= + +lodash._root@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" + integrity sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI= + +lodash.escape@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698" + integrity sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg= + dependencies: + lodash._root "^3.0.0" + +lodash.isarguments@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= + +lodash.isarray@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + integrity sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U= + +lodash.isfinite@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz#fb89b65a9a80281833f0b7478b3a5104f898ebb3" + integrity sha1-+4m2WpqAKBgz8LdHizpRBPiY67M= + +lodash.keys@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + integrity sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo= + dependencies: + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + +lodash.memoize@~3.0.3: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f" + integrity sha1-LcvSwofLwKVcxCMovQxzYVDVPj8= + +lodash.restparam@^3.0.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU= + +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= + +lodash.template@^3.0.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f" + integrity sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8= + dependencies: + lodash._basecopy "^3.0.0" + lodash._basetostring "^3.0.0" + lodash._basevalues "^3.0.0" + lodash._isiterateecall "^3.0.0" + lodash._reinterpolate "^3.0.0" + lodash.escape "^3.0.0" + lodash.keys "^3.0.0" + lodash.restparam "^3.0.0" + lodash.templatesettings "^3.0.0" + +lodash.templatesettings@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz#fb307844753b66b9f1afa54e262c745307dba8e5" + integrity sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU= + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.escape "^3.0.0" + +lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@~4.17.10: + version "4.17.20" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" + integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== + +loglevel@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.0.tgz#728166855a740d59d38db01cf46f042caa041bb0" + integrity sha512-i2sY04nal5jDcagM3FMfG++T69GEEM8CYuOfeOIvmXzOIcwE9a/CJPR0MFM97pYMj/u10lzz7/zd7+qwhrBTqQ== + +loud-rejection@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= + dependencies: + currently-unhandled "^0.4.1" + signal-exit "^3.0.0" + +lower-case@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" + integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw= + +lru-cache@^4.0.1: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + +lru-queue@0.1: + version "0.1.0" + resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3" + integrity sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM= + dependencies: + es5-ext "~0.10.2" + +make-dir@^2.0.0, make-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + +make-dir@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +make-iterator@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/make-iterator/-/make-iterator-1.0.1.tgz#29b33f312aa8f547c4a5e490f56afcec99133ad6" + integrity sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw== + dependencies: + kind-of "^6.0.2" + +makeerror@1.0.x: + version "1.0.11" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= + dependencies: + tmpl "1.0.x" + +map-cache@^0.2.0, map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + +map-obj@^1.0.0, map-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= + +map-stream@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.0.7.tgz#8a1f07896d82b10926bd3744a2420009f88974a8" + integrity sha1-ih8HiW2CsQkmvTdEokIACfiJdKg= + +map-stream@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/map-stream/-/map-stream-0.1.0.tgz#e56aa94c4c8055a16404a0674b78f215f7c8e194" + integrity sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ= + +map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + +matchdep@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/matchdep/-/matchdep-2.0.0.tgz#c6f34834a0d8dbc3b37c27ee8bbcb27c7775582e" + integrity sha1-xvNINKDY28OzfCfui7yyfHd1WC4= + dependencies: + findup-sync "^2.0.0" + micromatch "^3.0.4" + resolve "^1.4.0" + stack-trace "0.0.10" + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +memoizee@^0.4.14: + version "0.4.14" + resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.14.tgz#07a00f204699f9a95c2d9e77218271c7cd610d57" + integrity sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg== + dependencies: + d "1" + es5-ext "^0.10.45" + es6-weak-map "^2.0.2" + event-emitter "^0.3.5" + is-promise "^2.1" + lru-queue "0.1" + next-tick "1" + timers-ext "^0.1.5" + +meow@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= + dependencies: + camelcase-keys "^2.0.0" + decamelize "^1.1.2" + loud-rejection "^1.0.0" + map-obj "^1.0.1" + minimist "^1.1.3" + normalize-package-data "^2.3.4" + object-assign "^4.0.1" + read-pkg-up "^1.0.1" + redent "^1.0.0" + trim-newlines "^1.0.0" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + 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.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + +micromatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" + integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== + dependencies: + braces "^3.0.1" + picomatch "^2.0.5" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@1.44.0: + version "1.44.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" + integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== + +mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: + version "2.1.27" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" + integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== + dependencies: + mime-db "1.44.0" + +mime@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== + +mime@1.6.0, mime@^1.3.4: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= + +minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.1.0, minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +mitt@^1.1.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mitt/-/mitt-1.2.0.tgz#cb24e6569c806e31bd4e3995787fe38a04fdf90d" + integrity sha512-r6lj77KlwqLhIUku9UWYes7KJtsczvolZkzp8hbaDPPaE24OmWl5s539Mytlj22siEQKosZ26qCBgda2PKwoJw== + +mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + +mkdirp-classic@^0.5.2: + version "0.5.3" + resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + +"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +module-deps@^6.2.3: + version "6.2.3" + resolved "https://registry.yarnpkg.com/module-deps/-/module-deps-6.2.3.tgz#15490bc02af4b56cf62299c7c17cba32d71a96ee" + integrity sha512-fg7OZaQBcL4/L+AK5f4iVqf9OMbCclXfy/znXRxTVhJSeW5AIlS9AwheYwDaXM3lVW7OBeaeUEY3gbaC6cLlSA== + dependencies: + JSONStream "^1.0.3" + browser-resolve "^2.0.0" + cached-path-relative "^1.0.2" + concat-stream "~1.6.0" + defined "^1.0.0" + detective "^5.2.0" + duplexer2 "^0.1.2" + inherits "^2.0.1" + parents "^1.0.0" + readable-stream "^2.0.2" + resolve "^1.4.0" + stream-combiner2 "^1.1.1" + subarg "^1.0.0" + through2 "^2.0.0" + xtend "^4.0.0" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + +ms@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== + +ms@2.1.2, ms@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +multipipe@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b" + integrity sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s= + dependencies: + duplexer2 "0.0.2" + +mute-stdout@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mute-stdout/-/mute-stdout-1.0.1.tgz#acb0300eb4de23a7ddeec014e3e96044b3472331" + integrity sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg== + +nan@^2.12.1, nan@^2.13.2: + version "2.14.2" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" + integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== + +nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + 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-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + +negotiator@0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== + +next-tick@1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" + integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== + +next-tick@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" + integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= + +nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + +no-case@^2.2.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" + integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ== + dependencies: + lower-case "^1.1.1" + +node-gyp@^3.8.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c" + integrity sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA== + dependencies: + fstream "^1.0.0" + glob "^7.0.3" + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1 || 2 || 3 || 4" + osenv "0" + request "^2.87.0" + rimraf "2" + semver "~5.3.0" + tar "^2.0.0" + which "1" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= + +node-modules-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" + integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= + +node-notifier@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.0.tgz#a7eee2d51da6d0f7ff5094bc7108c911240c1620" + integrity sha512-46z7DUmcjoYdaWyXouuFNNfUo6eFa94t23c53c+lG/9Cvauk4a98rAUp9672X5dxGdQmLpPzTxzu8f/OeEPaFA== + dependencies: + growly "^1.3.0" + is-wsl "^2.2.0" + semver "^7.3.2" + shellwords "^0.1.1" + uuid "^8.3.0" + which "^2.0.2" + +node-releases@^1.1.65: + version "1.1.65" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.65.tgz#52d9579176bd60f23eba05c4438583f341944b81" + integrity sha512-YpzJOe2WFIW0V4ZkJQd/DGR/zdVwc/pI4Nl1CZrBO19FdRcSTmsuhdttw9rsTzzJLrNcSloLiBbEYx1C4f6gpA== + +node-sass@^4.8.3: + version "4.14.1" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.14.1.tgz#99c87ec2efb7047ed638fb4c9db7f3a42e2217b5" + integrity sha512-sjCuOlvGyCJS40R8BscF5vhVlQjNN069NtQ1gSxyK1u9iqvn6tf7O1R4GNowVZfiZUCRt5MmMs1xd+4V/7Yr0g== + dependencies: + async-foreach "^0.1.3" + chalk "^1.1.1" + cross-spawn "^3.0.0" + gaze "^1.0.0" + get-stdin "^4.0.1" + glob "^7.0.3" + in-publish "^2.0.0" + lodash "^4.17.15" + meow "^3.7.0" + mkdirp "^0.5.1" + nan "^2.13.2" + node-gyp "^3.8.0" + npmlog "^4.0.0" + request "^2.88.0" + sass-graph "2.2.5" + stdout-stream "^1.4.0" + "true-case-path" "^1.0.2" + +"nopt@2 || 3": + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= + dependencies: + abbrev "1" + +normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= + +now-and-later@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/now-and-later/-/now-and-later-2.0.1.tgz#8e579c8685764a7cc02cb680380e94f43ccb1f7c" + integrity sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ== + dependencies: + once "^1.3.2" + +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + +npm-run-path@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + integrity sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4= + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +nwsapi@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" + integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== + +o-stream@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/o-stream/-/o-stream-0.2.2.tgz#7fe03af870b8f9537af33b312b381b3034ab410f" + integrity sha512-V3j76KU3g/Gyl8rpdi2z72rn5zguMvTCQgAXfBe3pxEefKqXmOUOD7mvx/mNjykdxGqDVfpSoo8r+WdrkWg/1Q== + +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" + integrity sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I= + +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +object-component@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE= + +object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + +object-inspect@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.8.0.tgz#df807e5ecf53a609cc6bfe93eac3cc7be5b3a9d0" + integrity sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA== + +object-keys@^1.0.12, object-keys@^1.0.6, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + +object.assign@^4.0.4, object.assign@^4.1.0, object.assign@^4.1.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" + object-keys "^1.1.1" + +object.defaults@^1.0.0, object.defaults@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/object.defaults/-/object.defaults-1.1.0.tgz#3a7f868334b407dea06da16d88d5cd29e435fecf" + integrity sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8= + dependencies: + array-each "^1.0.1" + array-slice "^1.0.0" + for-own "^1.0.0" + isobject "^3.0.0" + +object.map@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object.map/-/object.map-1.0.1.tgz#cf83e59dc8fcc0ad5f4250e1f78b3b81bd801d37" + integrity sha1-z4Plncj8wK1fQlDh94s7gb2AHTc= + dependencies: + for-own "^1.0.0" + make-iterator "^1.0.0" + +object.pick@^1.2.0, object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + +object.reduce@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object.reduce/-/object.reduce-1.0.1.tgz#6fe348f2ac7fa0f95ca621226599096825bb03ad" + integrity sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60= + dependencies: + for-own "^1.0.0" + make-iterator "^1.0.0" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + +once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +onetime@^5.1.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +openurl@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/openurl/-/openurl-1.1.1.tgz#3875b4b0ef7a52c156f0db41d4609dbb0f94b387" + integrity sha1-OHW0sO96UsFW8NtB1GCduw+Us4c= + +opn@5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.3.0.tgz#64871565c863875f052cfdf53d3e3cb5adb53b1c" + integrity sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g== + dependencies: + is-wsl "^1.1.0" + +optionator@^0.8.0, optionator@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + +ordered-read-streams@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz#77c0cb37c41525d64166d990ffad7ec6a0e1363e" + integrity sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4= + dependencies: + readable-stream "^2.0.1" + +os-browserify@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= + +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk= + dependencies: + lcid "^1.0.0" + +os-tmpdir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +osenv@0: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-each-series@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.1.0.tgz#961c8dd3f195ea96c747e636b262b800a6b1af48" + integrity sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ== + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + +p-limit@^2.0.0, p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +pako@~1.0.5: + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + +param-case@2.1.x: + version "2.1.1" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247" + integrity sha1-35T9jPZTHs915r75oIWPvHK+Ikc= + dependencies: + no-case "^2.2.0" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parents@^1.0.0, parents@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parents/-/parents-1.0.1.tgz#fedd4d2bf193a77745fe71e371d73c3307d9c751" + integrity sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E= + dependencies: + path-platform "~0.11.15" + +parse-asn1@^5.0.0, parse-asn1@^5.1.5: + version "5.1.6" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" + integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== + dependencies: + asn1.js "^5.2.0" + browserify-aes "^1.0.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" + +parse-filepath@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.2.tgz#a632127f53aaf3d15876f5872f3ffac763d6c891" + integrity sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE= + dependencies: + is-absolute "^1.0.0" + map-cache "^0.2.0" + path-root "^0.1.1" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= + dependencies: + error-ex "^1.2.0" + +parse-json@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.1.0.tgz#f96088cdf24a8faa9aea9a009f2d9d942c999646" + integrity sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parse-node-version@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b" + integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA== + +parse-passwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= + +parse5@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" + integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== + +parseqs@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + integrity sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0= + dependencies: + better-assert "~1.0.0" + +parseqs@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.6.tgz#8e4bb5a19d1cdc844a08ac974d34e273afa670d5" + integrity sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w== + +parseuri@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + integrity sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo= + dependencies: + better-assert "~1.0.0" + +parseuri@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.6.tgz#e1496e829e3ac2ff47f39a4dd044b32823c4a25a" + integrity sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow== + +parseurl@~1.3.2, parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + +path-browserify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" + integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== + +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= + dependencies: + pinkie-promise "^2.0.0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + +path-platform@~0.11.15: + version "0.11.15" + resolved "https://registry.yarnpkg.com/path-platform/-/path-platform-0.11.15.tgz#e864217f74c36850f0852b78dc7bf7d4a5721bf2" + integrity sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I= + +path-root-regex@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d" + integrity sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0= + +path-root@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7" + integrity sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc= + dependencies: + path-root-regex "^0.1.0" + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +pbkdf2@^3.0.3: + version "3.1.1" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.1.tgz#cb8724b0fada984596856d1a6ebafd3584654b94" + integrity sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" + integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= + +pirates@^4.0.0, pirates@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" + integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== + dependencies: + node-modules-regexp "^1.0.0" + +pkg-dir@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== + dependencies: + find-up "^3.0.0" + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +plexer@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/plexer/-/plexer-1.0.1.tgz#a801b652bf8145739795ea4d3bf0af946c30c0dd" + integrity sha1-qAG2Ur+BRXOXlepNO/CvlGwwwN0= + dependencies: + isstream "^0.1.2" + readable-stream "^2.0.2" + +plugin-error@1.0.1, plugin-error@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-1.0.1.tgz#77016bd8919d0ac377fdcdd0322328953ca5781c" + integrity sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA== + dependencies: + ansi-colors "^1.0.1" + arr-diff "^4.0.0" + arr-union "^3.1.0" + extend-shallow "^3.0.2" + +portscanner@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/portscanner/-/portscanner-2.1.1.tgz#eabb409e4de24950f5a2a516d35ae769343fbb96" + integrity sha1-6rtAnk3iSVD1oqUW01rnaTQ/u5Y= + dependencies: + async "1.5.2" + is-number-like "^1.0.3" + +posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + +postcss-value-parser@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" + integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== + +postcss@^7.0.17, postcss@^7.0.32: + version "7.0.35" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.35.tgz#d2be00b998f7f211d8a276974079f2e92b970e24" + integrity sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg== + dependencies: + chalk "^2.4.2" + source-map "^0.6.1" + supports-color "^6.1.0" + +prelude-ls@^1.1.2, prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + +pretty-bytes@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-3.0.1.tgz#27d0008d778063a0b4811bb35c79f1bd5d5fbccf" + integrity sha1-J9AAjXeAY6C0gRuzXHnxvV1fvM8= + dependencies: + number-is-nan "^1.0.0" + +pretty-format@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" + integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== + dependencies: + "@jest/types" "^26.6.2" + ansi-regex "^5.0.0" + ansi-styles "^4.0.0" + react-is "^17.0.1" + +pretty-hrtime@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" + integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE= + +process-nextick-args@^2.0.0, process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process@~0.11.0: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +prompts@^2.0.1: + version "2.4.0" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.0.tgz#4aa5de0723a231d1ee9121c40fdf663df73f61d7" + integrity sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + +psl@^1.1.28: + version "1.8.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + +public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +pump@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pumpify@^1.3.5: + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= + +punycode@^1.3.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= + +punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +qs@6.2.3: + version "6.2.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.3.tgz#1cfcb25c10a9b2b483053ff39f5dfc9233908cfe" + integrity sha1-HPyyXBCpsrSDBT/zn138kjOQjP4= + +qs@^6.4.0: + version "6.9.4" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687" + integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ== + +qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + +querystring-es3@~0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +range-parser@~1.2.0, range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@^2.3.2: + version "2.4.1" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.1.tgz#30ac82f98bb5ae8c152e67149dac8d55153b168c" + integrity sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA== + dependencies: + bytes "3.1.0" + http-errors "1.7.3" + iconv-lite "0.4.24" + unpipe "1.0.0" + +raw-body@~1.1.0: + version "1.1.7" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-1.1.7.tgz#1d027c2bfa116acc6623bca8f00016572a87d425" + integrity sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU= + dependencies: + bytes "1" + string_decoder "0.10" + +react-is@^17.0.1: + version "17.0.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339" + integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA== + +read-only-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-only-stream/-/read-only-stream-2.0.0.tgz#2724fd6a8113d73764ac288d4386270c1dbf17f0" + integrity sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A= + dependencies: + readable-stream "^2.0.2" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg-up@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" + integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== + dependencies: + find-up "^4.1.0" + read-pkg "^5.2.0" + type-fest "^0.8.1" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +read-pkg@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" + integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== + dependencies: + "@types/normalize-package-data" "^2.4.0" + normalize-package-data "^2.5.0" + parse-json "^5.0.0" + type-fest "^0.6.0" + +"readable-stream@2 || 3", readable-stream@3, readable-stream@^3.1.1, readable-stream@^3.5.0, readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@~1.1.9: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readdirp@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== + dependencies: + graceful-fs "^4.1.11" + micromatch "^3.1.10" + readable-stream "^2.0.2" + +readdirp@~3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" + integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ== + dependencies: + picomatch "^2.2.1" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= + dependencies: + resolve "^1.1.6" + +redent@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= + dependencies: + indent-string "^2.1.0" + strip-indent "^1.0.1" + +regenerate-unicode-properties@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" + integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== + dependencies: + regenerate "^1.4.0" + +regenerate@^1.4.0: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.13.4: + version "0.13.7" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55" + integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew== + +regenerator-transform@^0.14.2: + version "0.14.5" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" + integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw== + dependencies: + "@babel/runtime" "^7.8.4" + +regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + +regexpp@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2" + integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== + +regexpu-core@^4.7.1: + version "4.7.1" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.1.tgz#2dea5a9a07233298fbf0db91fa9abc4c6e0f8ad6" + integrity sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ== + dependencies: + regenerate "^1.4.0" + regenerate-unicode-properties "^8.2.0" + regjsgen "^0.5.1" + regjsparser "^0.6.4" + unicode-match-property-ecmascript "^1.0.4" + unicode-match-property-value-ecmascript "^1.2.0" + +regjsgen@^0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.2.tgz#92ff295fb1deecbf6ecdab2543d207e91aa33733" + integrity sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A== + +regjsparser@^0.6.4: + version "0.6.4" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272" + integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== + dependencies: + jsesc "~0.5.0" + +relateurl@0.2.x: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= + +remove-bom-buffer@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz#c2bf1e377520d324f623892e33c10cac2c252b53" + integrity sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ== + dependencies: + is-buffer "^1.1.5" + is-utf8 "^0.2.1" + +remove-bom-stream@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz#05f1a593f16e42e1fb90ebf59de8e569525f9523" + integrity sha1-BfGlk/FuQuH7kOv1nejlaVJflSM= + dependencies: + remove-bom-buffer "^3.0.0" + safe-buffer "^5.1.0" + through2 "^2.0.3" + +remove-trailing-separator@^1.0.1, remove-trailing-separator@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + +repeat-element@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= + dependencies: + is-finite "^1.0.0" + +replace-ext@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" + integrity sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ= + +replace-ext@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.1.tgz#2d6d996d04a15855d967443631dd5f77825b016a" + integrity sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw== + +replace-homedir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/replace-homedir/-/replace-homedir-1.0.0.tgz#e87f6d513b928dde808260c12be7fec6ff6e798c" + integrity sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw= + dependencies: + homedir-polyfill "^1.0.1" + is-absolute "^1.0.0" + remove-trailing-separator "^1.1.0" + +request-promise-core@1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f" + integrity sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw== + dependencies: + lodash "^4.17.19" + +request-promise-native@^1.0.8: + version "1.0.9" + resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.9.tgz#e407120526a5efdc9a39b28a5679bf47b9d9dc28" + integrity sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g== + dependencies: + request-promise-core "1.1.4" + stealthy-require "^1.1.1" + tough-cookie "^2.3.3" + +request@^2.67.0, request@^2.87.0, request@^2.88.0, request@^2.88.2: + version "2.88.2" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= + +require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-dir@^1.0.0, resolve-dir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" + integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M= + dependencies: + expand-tilde "^2.0.0" + global-modules "^1.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve-options@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/resolve-options/-/resolve-options-1.1.0.tgz#32bb9e39c06d67338dc9378c0d6d6074566ad131" + integrity sha1-MrueOcBtZzONyTeMDW1gdFZq0TE= + dependencies: + value-or-function "^3.0.0" + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + +resolve@^1.1.4, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.17.0, resolve@^1.18.1, resolve@^1.3.2, resolve@^1.4.0: + version "1.18.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.18.1.tgz#018fcb2c5b207d2a6424aee361c5a266da8f4130" + integrity sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA== + dependencies: + is-core-module "^2.0.0" + path-parse "^1.0.6" + +resp-modifier@6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/resp-modifier/-/resp-modifier-6.0.2.tgz#b124de5c4fbafcba541f48ffa73970f4aa456b4f" + integrity sha1-sSTeXE+6/LpUH0j/pzlw9KpFa08= + dependencies: + debug "^2.2.0" + minimatch "^3.0.2" + +ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@2: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@2.6.3: + version "2.6.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" + integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== + dependencies: + glob "^7.1.3" + +rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +rsvp@^4.8.4: + version "4.8.5" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" + integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== + +rtcpeerconnection-shim@^1.2.15: + version "1.2.15" + resolved "https://registry.yarnpkg.com/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.15.tgz#e7cc189a81b435324c4949aa3dfb51888684b243" + integrity sha512-C6DxhXt7bssQ1nHb154lqeL0SXz5Dx4RczXZu2Aa/L1NJFnEVDxFwCBo3fqtuljhHIGceg5JKBV4XJ0gW5JKyw== + dependencies: + sdp "^2.6.0" + +run-parallel@^1.1.9: + version "1.1.10" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.10.tgz#60a51b2ae836636c81377df16cb107351bcd13ef" + integrity sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw== + +rx@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" + integrity sha1-pfE/957zt0D+MKqAP7CfmIBdR4I= + +rxjs@^5.5.6: + version "5.5.12" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.12.tgz#6fa61b8a77c3d793dbaf270bee2f43f652d741cc" + integrity sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw== + dependencies: + symbol-observable "1.0.1" + +safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-json-parse@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/safe-json-parse/-/safe-json-parse-1.0.1.tgz#3e76723e38dfdda13c9b1d29a1e07ffee4b30b57" + integrity sha1-PnZyPjjf3aE8mx0poeB//uSzC1c= + +safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sane@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" + integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== + dependencies: + "@cnakazawa/watch" "^1.0.3" + anymatch "^2.0.0" + capture-exit "^2.0.0" + exec-sh "^0.3.2" + execa "^1.0.0" + fb-watchman "^2.0.0" + micromatch "^3.1.4" + minimist "^1.1.1" + walker "~1.0.5" + +sass-graph@2.2.5: + version "2.2.5" + resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.5.tgz#a981c87446b8319d96dce0671e487879bd24c2e8" + integrity sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag== + dependencies: + glob "^7.0.0" + lodash "^4.0.0" + scss-tokenizer "^0.2.3" + yargs "^13.3.2" + +saxes@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== + dependencies: + xmlchars "^2.2.0" + +scss-tokenizer@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1" + integrity sha1-jrBtualyMzOCTT9VMGQRSYR85dE= + dependencies: + js-base64 "^2.1.8" + source-map "^0.4.2" + +sdp@^2.12.0, sdp@^2.6.0: + version "2.12.0" + resolved "https://registry.yarnpkg.com/sdp/-/sdp-2.12.0.tgz#338a106af7560c86e4523f858349680350d53b22" + integrity sha512-jhXqQAQVM+8Xj5EjJGVweuEzgtGWb3tmEEpl3CLP3cStInSbVHSg0QWOGQzNq8pSID4JkpeV2mPqlMDLrm0/Vw== + +semver-greatest-satisfied-range@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz#13e8c2658ab9691cb0cd71093240280d36f77a5b" + integrity sha1-E+jCZYq5aRywzXEJMkAoDTb3els= + dependencies: + sver-compat "^1.5.0" + +"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + +semver@^6.0.0, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + +semver@^7.2.1, semver@^7.3.2: + version "7.3.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" + integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== + +semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= + +send@0.16.2, send@^0.16.2: + version "0.16.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" + integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.6.2" + mime "1.4.1" + ms "2.0.0" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.4.0" + +send@0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" + integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.7.2" + mime "1.6.0" + ms "2.1.1" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + +serve-index@1.9.1, serve-index@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= + dependencies: + accepts "~1.3.4" + batch "0.6.1" + debug "2.6.9" + escape-html "~1.0.3" + http-errors "~1.6.2" + mime-types "~2.1.17" + parseurl "~1.3.2" + +serve-static@1.13.2: + version "1.13.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" + integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.2" + send "0.16.2" + +serve-static@^1.13.2: + version "1.14.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" + integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.1" + +server-destroy@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/server-destroy/-/server-destroy-1.0.1.tgz#f13bf928e42b9c3e79383e61cc3998b5d14e6cdd" + integrity sha1-8Tv5KOQrnD55OD5hzDmYtdFObN0= + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + +set-value@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-3.0.2.tgz#74e8ecd023c33d0f77199d415409a40f21e61b90" + integrity sha512-npjkVoz+ank0zjlV9F47Fdbjfj/PfXyVhZvGALWsyIYU/qrMzpi6avjKW3/7KeSU2Df3I46BrN1xOI1+6vW0hA== + dependencies: + is-plain-object "^2.0.4" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +setprototypeof@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" + integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shasum-object@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shasum-object/-/shasum-object-1.0.0.tgz#0b7b74ff5b66ecf9035475522fa05090ac47e29e" + integrity sha512-Iqo5rp/3xVi6M4YheapzZhhGPVs0yZwHj7wvwQ1B9z8H6zk+FEnI7y3Teq7qwnekfEhu8WmG2z0z4iWZaxLWVg== + dependencies: + fast-safe-stringify "^2.0.7" + +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shell-quote@^1.6.1: + version "1.7.2" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" + integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== + +shellwords@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" + integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + +simple-concat@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" + integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" + integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== + dependencies: + ansi-styles "^3.2.0" + astral-regex "^1.0.0" + is-fullwidth-code-point "^2.0.0" + +snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + +snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + +snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + 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.0" + use "^3.1.0" + +socket.io-adapter@~1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9" + integrity sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g== + +socket.io-client@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.1.1.tgz#dcb38103436ab4578ddb026638ae2f21b623671f" + integrity sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ== + dependencies: + backo2 "1.0.2" + base64-arraybuffer "0.1.5" + component-bind "1.0.0" + component-emitter "1.2.1" + debug "~3.1.0" + engine.io-client "~3.2.0" + has-binary2 "~1.0.2" + has-cors "1.1.0" + indexof "0.0.1" + object-component "0.0.3" + parseqs "0.0.5" + parseuri "0.0.5" + socket.io-parser "~3.2.0" + to-array "0.1.4" + +socket.io-client@^2.0.4: + version "2.3.1" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.3.1.tgz#91a4038ef4d03c19967bb3c646fec6e0eaa78cff" + integrity sha512-YXmXn3pA8abPOY//JtYxou95Ihvzmg8U6kQyolArkIyLd0pgVhrfor/iMsox8cn07WCOOvvuJ6XKegzIucPutQ== + dependencies: + backo2 "1.0.2" + component-bind "1.0.0" + component-emitter "~1.3.0" + debug "~3.1.0" + engine.io-client "~3.4.0" + has-binary2 "~1.0.2" + indexof "0.0.1" + parseqs "0.0.6" + parseuri "0.0.6" + socket.io-parser "~3.3.0" + to-array "0.1.4" + +socket.io-parser@~3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.2.0.tgz#e7c6228b6aa1f814e6148aea325b51aa9499e077" + integrity sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA== + dependencies: + component-emitter "1.2.1" + debug "~3.1.0" + isarray "2.0.1" + +socket.io-parser@~3.3.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.1.tgz#f07d9c8cb3fb92633aa93e76d98fd3a334623199" + integrity sha512-1QLvVAe8dTz+mKmZ07Swxt+LAo4Y1ff50rlyoEx00TQmDFVQYPfcqGvIDJLGaBdhdNCecXtyKpD+EgKGcmmbuQ== + dependencies: + component-emitter "~1.3.0" + debug "~3.1.0" + isarray "2.0.1" + +socket.io@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.1.1.tgz#a069c5feabee3e6b214a75b40ce0652e1cfb9980" + integrity sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA== + dependencies: + debug "~3.1.0" + engine.io "~3.2.0" + has-binary2 "~1.0.2" + socket.io-adapter "~1.1.0" + socket.io-client "2.1.1" + socket.io-parser "~3.2.0" + +source-map-resolve@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-support@^0.5.16, source-map-support@^0.5.6, source-map-support@~0.5.12: + version "0.5.19" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" + integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + +source-map@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + integrity sha1-66T12pwNyZneaAMti092FzZSA2s= + dependencies: + amdefine ">=0.0.4" + +source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.6, source-map@~0.5.3: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@^0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + +sparkles@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.1.tgz#008db65edce6c50eec0c5e228e1945061dd0437c" + integrity sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw== + +spdx-correct@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" + integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.6" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz#c80757383c28abf7296744998cbc106ae8b854ce" + integrity sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw== + +split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + +split-string@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-6.1.0.tgz#e9cedcf94cdab077d9b5528927894dec4b0f42ab" + integrity sha512-9UBdnmnvx2NLLd4bMs7CEKK+wSzbujVv3ONyorkP1o8M3pVJQtXDO1cN19xD1JJs6ltOrtPrkUND0HzLSinUcA== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + +sshpk@^1.7.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +stack-trace@0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" + integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA= + +stack-utils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.2.tgz#5cf48b4557becb4638d0bc4f21d23f5d19586593" + integrity sha512-0H7QK2ECz3fyZMzQ8rH0j2ykpfbnd20BFtfg/SqVC2+sCTtcw0aDTGB7dk+de4U4uUeuz6nOtJcrkFFLG1B0Rg== + dependencies: + escape-string-regexp "^2.0.0" + +static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + +"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + +statuses@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + integrity sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4= + +statuses@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== + +stdout-stream@^1.4.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.1.tgz#5ac174cdd5cd726104aa0c0b2bd83815d8d535de" + integrity sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA== + dependencies: + readable-stream "^2.0.1" + +stealthy-require@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" + integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= + +stream-browserify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" + integrity sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA== + dependencies: + inherits "~2.0.4" + readable-stream "^3.5.0" + +stream-combiner2@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stream-combiner2/-/stream-combiner2-1.1.1.tgz#fb4d8a1420ea362764e21ad4780397bebcb41cbe" + integrity sha1-+02KFCDqNidk4hrUeAOXvry0HL4= + dependencies: + duplexer2 "~0.1.0" + readable-stream "^2.0.2" + +stream-exhaust@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/stream-exhaust/-/stream-exhaust-1.0.2.tgz#acdac8da59ef2bc1e17a2c0ccf6c320d120e555d" + integrity sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw== + +stream-http@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-3.1.1.tgz#0370a8017cf8d050b9a8554afe608f043eaff564" + integrity sha512-S7OqaYu0EkFpgeGFb/NPOoPLxFko7TPqtEeFg5DXPB4v/KETHG0Ln6fRFrNezoelpaDKmycEmmZ81cC9DAwgYg== + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.4" + readable-stream "^3.6.0" + xtend "^4.0.2" + +stream-shift@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" + integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== + +stream-splicer@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/stream-splicer/-/stream-splicer-2.0.1.tgz#0b13b7ee2b5ac7e0609a7463d83899589a363fcd" + integrity sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg== + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.2" + +stream-throttle@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/stream-throttle/-/stream-throttle-0.1.3.tgz#add57c8d7cc73a81630d31cd55d3961cfafba9c3" + integrity sha1-rdV8jXzHOoFjDTHNVdOWHPr7qcM= + dependencies: + commander "^2.2.0" + limiter "^1.0.5" + +stream-to-array@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/stream-to-array/-/stream-to-array-2.3.0.tgz#bbf6b39f5f43ec30bc71babcb37557acecf34353" + integrity sha1-u/azn19D7DC8cbq8s3VXrOzzQ1M= + dependencies: + any-promise "^1.1.0" + +string-length@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.1.tgz#4a973bf31ef77c4edbceadd6af2611996985f8a1" + integrity sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-template@~0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" + integrity sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0= + +string-width@^1.0.1, string-width@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2": + version "2.1.1" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" + integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + +string-width@^3.0.0, string-width@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== + dependencies: + emoji-regex "^7.0.1" + is-fullwidth-code-point "^2.0.0" + strip-ansi "^5.1.0" + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" + integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + +string.prototype.trimend@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.2.tgz#6ddd9a8796bc714b489a3ae22246a208f37bfa46" + integrity sha512-8oAG/hi14Z4nOVP0z6mdiVZ/wqjDtWSLygMigTzAb+7aPEDTleeFf+WrF+alzecxIRkckkJVn+dTlwzJXORATw== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.18.0-next.1" + +string.prototype.trimstart@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.2.tgz#22d45da81015309cd0cdd79787e8919fc5c613e7" + integrity sha512-7F6CdBTl5zyu30BJFdzSTlSlLPwODC23Od+iLoVH8X6+3fvDPPuBVVj9iaB1GOsSTSIgVfsfm27R2FGrAPznWg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.18.0-next.1" + +string_decoder@0.10, string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= + dependencies: + ansi-regex "^3.0.0" + +strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== + dependencies: + ansi-regex "^4.1.0" + +strip-ansi@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== + dependencies: + ansi-regex "^5.0.0" + +strip-ansi@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991" + integrity sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE= + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= + dependencies: + is-utf8 "^0.2.0" + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-indent@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= + dependencies: + get-stdin "^4.0.1" + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +subarg@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2" + integrity sha1-9izxdYHplrSPyWVpn1TAauJouNI= + dependencies: + minimist "^1.1.0" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" + integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.0.0, supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-hyperlinks@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz#f663df252af5f37c5d49bbd7eeefa9e0b9e59e47" + integrity sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + +sver-compat@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/sver-compat/-/sver-compat-1.5.0.tgz#3cf87dfeb4d07b4a3f14827bc186b3fd0c645cd8" + integrity sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg= + dependencies: + es6-iterator "^2.0.1" + es6-symbol "^3.1.1" + +symbol-observable@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" + integrity sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ= + +symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + +syntax-error@^1.1.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/syntax-error/-/syntax-error-1.4.0.tgz#2d9d4ff5c064acb711594a3e3b95054ad51d907c" + integrity sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w== + dependencies: + acorn-node "^1.2.0" + +table@^5.2.3: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== + dependencies: + ajv "^6.10.2" + lodash "^4.17.14" + slice-ansi "^2.1.0" + string-width "^3.0.0" + +tar@^2.0.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.2.tgz#0ca8848562c7299b8b446ff6a4d60cdbb23edc40" + integrity sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA== + dependencies: + block-stream "*" + fstream "^1.0.12" + inherits "2" + +terminal-link@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== + dependencies: + ansi-escapes "^4.2.1" + supports-hyperlinks "^2.0.0" + +ternary-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ternary-stream/-/ternary-stream-3.0.0.tgz#7951930ea9e823924d956f03d516151a2d516253" + integrity sha512-oIzdi+UL/JdktkT+7KU5tSIQjj8pbShj3OASuvDEhm0NT5lppsm7aXWAmAq4/QMaBIyfuEcNLbAQA+HpaISobQ== + dependencies: + duplexify "^4.1.1" + fork-stream "^0.0.4" + merge-stream "^2.0.0" + through2 "^3.0.1" + +terser@^4.3.9: + version "4.8.0" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" + integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== + dependencies: + commander "^2.20.0" + source-map "~0.6.1" + source-map-support "~0.5.12" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + +tfunk@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/tfunk/-/tfunk-4.0.0.tgz#de9399feaf2060901d590b7faad80fcd5443077e" + integrity sha512-eJQ0dGfDIzWNiFNYFVjJ+Ezl/GmwHaFTBTjrtqNPW0S7cuVDBrZrmzUz6VkMeCR4DZFqhd4YtLwsw3i2wYHswQ== + dependencies: + chalk "^1.1.3" + dlv "^1.1.3" + +throat@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" + integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== + +through2-filter@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-3.0.0.tgz#700e786df2367c2c88cd8aa5be4cf9c1e7831254" + integrity sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA== + dependencies: + through2 "~2.0.0" + xtend "~4.0.0" + +through2@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.1.tgz#39276e713c3302edf9e388dd9c812dd3b825bd5a" + integrity sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww== + dependencies: + readable-stream "2 || 3" + +through2@^2.0.0, through2@^2.0.3, through2@~2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +through2@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.2.tgz#99f88931cfc761ec7678b41d5d7336b5b6a07bf4" + integrity sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ== + dependencies: + inherits "^2.0.4" + readable-stream "2 || 3" + +through2@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" + integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw== + dependencies: + readable-stream "3" + +"through@>=2.2.7 <3", through@^2.3.7: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + +time-stamp@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" + integrity sha1-dkpaEa9QVhkhsTPztE5hhofg9cM= + +timers-browserify@^1.0.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-1.4.2.tgz#c9c58b575be8407375cb5e2462dacee74359f41d" + integrity sha1-ycWLV1voQHN1y14kYtrO50NZ9B0= + dependencies: + process "~0.11.0" + +timers-ext@^0.1.5: + version "0.1.7" + resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.7.tgz#6f57ad8578e07a3fb9f91d9387d65647555e25c6" + integrity sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ== + dependencies: + es5-ext "~0.10.46" + next-tick "1" + +tiny-lr@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-1.1.1.tgz#9fa547412f238fedb068ee295af8b682c98b2aab" + integrity sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA== + dependencies: + body "^5.1.0" + debug "^3.1.0" + faye-websocket "~0.10.0" + livereload-js "^2.3.0" + object-assign "^4.1.0" + qs "^6.4.0" + +tmpl@1.0.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= + +to-absolute-glob@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz#1865f43d9e74b0822db9f145b78cff7d0f7c849b" + integrity sha1-GGX0PZ50sIItufFFt4z/fQ98hJs= + dependencies: + is-absolute "^1.0.0" + is-negated-glob "^1.0.0" + +to-array@0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA= + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + +to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + +to-through@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-through/-/to-through-2.0.0.tgz#fc92adaba072647bc0b67d6b03664aa195093af6" + integrity sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY= + dependencies: + through2 "^2.0.3" + +toidentifier@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" + integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== + +tough-cookie@^2.3.3, tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + +tough-cookie@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2" + integrity sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg== + dependencies: + ip-regex "^2.1.0" + psl "^1.1.28" + punycode "^2.1.1" + +tr46@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.0.2.tgz#03273586def1595ae08fedb38d7733cee91d2479" + integrity sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg== + dependencies: + punycode "^2.1.1" + +trim-newlines@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= + +"true-case-path@^1.0.2": + version "1.0.3" + resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.3.tgz#f813b5a8c86b40da59606722b144e3225799f47d" + integrity sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew== + dependencies: + glob "^7.1.2" + +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tsutils@^3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" + integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== + dependencies: + tslib "^1.8.1" + +tty-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" + integrity sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw== + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + dependencies: + prelude-ls "~1.1.2" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" + integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== + +type-fest@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" + integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + +type@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" + integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== + +type@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/type/-/type-2.1.0.tgz#9bdc22c648cf8cf86dd23d32336a41cfb6475e3f" + integrity sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA== + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + +ua-parser-js@^0.7.18: + version "0.7.22" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.22.tgz#960df60a5f911ea8f1c818f3747b99c6e177eae3" + integrity sha512-YUxzMjJ5T71w6a8WWVcMGM6YWOTX27rCoIQgLXiWaxqXSx9D7DNjiGWn1aJIRSQ5qr0xuhra77bSIh6voR/46Q== + +uglify-js@3.4.x: + version "3.4.10" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f" + integrity sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw== + dependencies: + commander "~2.19.0" + source-map "~0.6.1" + +ultron@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" + integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og== + +umd@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/umd/-/umd-3.0.3.tgz#aa9fe653c42b9097678489c01000acb69f0b26cf" + integrity sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow== + +unc-path-regex@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" + integrity sha1-5z3T17DXxe2G+6xrCufYxqadUPo= + +undeclared-identifiers@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz#9254c1d37bdac0ac2b52de4b6722792d2a91e30f" + integrity sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw== + dependencies: + acorn-node "^1.3.0" + dash-ast "^1.0.0" + get-assigned-identifiers "^1.2.0" + simple-concat "^1.0.0" + xtend "^4.0.1" + +undertaker-registry@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/undertaker-registry/-/undertaker-registry-1.0.1.tgz#5e4bda308e4a8a2ae584f9b9a4359a499825cc50" + integrity sha1-XkvaMI5KiirlhPm5pDWaSZglzFA= + +undertaker@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/undertaker/-/undertaker-1.3.0.tgz#363a6e541f27954d5791d6fa3c1d321666f86d18" + integrity sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg== + dependencies: + arr-flatten "^1.0.1" + arr-map "^2.0.0" + bach "^1.0.0" + collection-map "^1.0.0" + es6-weak-map "^2.0.1" + fast-levenshtein "^1.0.0" + last-run "^1.1.0" + object.defaults "^1.0.0" + object.reduce "^1.0.0" + undertaker-registry "^1.0.0" + +unicode-canonical-property-names-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" + integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== + +unicode-match-property-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" + integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== + dependencies: + unicode-canonical-property-names-ecmascript "^1.0.4" + unicode-property-aliases-ecmascript "^1.0.4" + +unicode-match-property-value-ecmascript@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" + integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== + +unicode-property-aliases-ecmascript@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" + integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== + +union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + +union-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-2.0.1.tgz#4e1ab0f99ab52c52a53e14d8039b5130fef682b8" + integrity sha512-NmcRHHhUy1qWmp6yYWsaURV2qwfS24TmTtO9S9x0L41wCNNVBQFD3toOzO0cd8SsNrFhbw/O0iYO5uffXGYocw== + dependencies: + get-value "^3.0.1" + set-value "^3.0.0" + +unique-stream@^2.0.2: + version "2.3.1" + resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-2.3.1.tgz#c65d110e9a4adf9a6c5948b28053d9a8d04cbeac" + integrity sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A== + dependencies: + json-stable-stringify-without-jsonify "^1.0.1" + through2-filter "^3.0.0" + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + +unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + +upath@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" + integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== + +upper-case@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" + integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg= + +uri-js@^4.2.2: + version "4.4.0" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.0.tgz#aa714261de793e8a82347a7bcc9ce74e86f28602" + integrity sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g== + dependencies: + punycode "^2.1.0" + +urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + +url@~0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +util@0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= + dependencies: + inherits "2.0.1" + +util@~0.12.0: + version "0.12.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.12.3.tgz#971bb0292d2cc0c892dab7c6a5d37c2bec707888" + integrity sha512-I8XkoQwE+fPQEhy9v012V+TSdH2kp9ts29i20TaaDUXsg7x/onePbhFJUExBfv/2ay1ZOp/Vsm3nDlmnFGSAog== + dependencies: + inherits "^2.0.3" + is-arguments "^1.0.4" + is-generator-function "^1.0.7" + is-typed-array "^1.1.3" + safe-buffer "^5.1.2" + which-typed-array "^1.1.2" + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + +uuid@^3.3.2, uuid@^3.3.3: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +uuid@^8.3.0: + version "8.3.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.1.tgz#2ba2e6ca000da60fce5a196954ab241131e05a31" + integrity sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg== + +v8-compile-cache@^2.0.3: + version "2.2.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz#9471efa3ef9128d2f7c6a7ca39c4dd6b5055b132" + integrity sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q== + +v8-to-istanbul@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-7.0.0.tgz#b4fe00e35649ef7785a9b7fcebcea05f37c332fc" + integrity sha512-fLL2rFuQpMtm9r8hrAV2apXX/WqHJ6+IC4/eQVdMDGBUgH/YMV4Gv3duk3kjmyg6uiQWBAA9nJwue4iJUOkHeA== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + source-map "^0.7.3" + +v8flags@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-3.2.0.tgz#b243e3b4dfd731fa774e7492128109a0fe66d656" + integrity sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg== + dependencies: + homedir-polyfill "^1.0.1" + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +value-or-function@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/value-or-function/-/value-or-function-3.0.0.tgz#1c243a50b595c1be54a754bfece8563b9ff8d813" + integrity sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM= + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vinyl-fs@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-3.0.3.tgz#c85849405f67428feabbbd5c5dbdd64f47d31bc7" + integrity sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng== + dependencies: + fs-mkdirp-stream "^1.0.0" + glob-stream "^6.1.0" + graceful-fs "^4.0.0" + is-valid-glob "^1.0.0" + lazystream "^1.0.0" + lead "^1.0.0" + object.assign "^4.0.4" + pumpify "^1.3.5" + readable-stream "^2.3.3" + remove-bom-buffer "^3.0.0" + remove-bom-stream "^1.2.0" + resolve-options "^1.1.0" + through2 "^2.0.0" + to-through "^2.0.0" + value-or-function "^3.0.0" + vinyl "^2.0.0" + vinyl-sourcemap "^1.1.0" + +vinyl-source-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/vinyl-source-stream/-/vinyl-source-stream-2.0.0.tgz#f38a5afb9dd1e93b65d550469ac6182ac4f54b8e" + integrity sha1-84pa+53R6Ttl1VBGmsYYKsT1S44= + dependencies: + through2 "^2.0.3" + vinyl "^2.1.0" + +vinyl-sourcemap@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz#92a800593a38703a8cdb11d8b300ad4be63b3e16" + integrity sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY= + dependencies: + append-buffer "^1.0.2" + convert-source-map "^1.5.0" + graceful-fs "^4.1.6" + normalize-path "^2.1.1" + now-and-later "^2.0.0" + remove-bom-buffer "^3.0.0" + vinyl "^2.0.0" + +vinyl-sourcemaps-apply@0.2.1, vinyl-sourcemaps-apply@^0.2.0, vinyl-sourcemaps-apply@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz#ab6549d61d172c2b1b87be5c508d239c8ef87705" + integrity sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU= + dependencies: + source-map "^0.5.1" + +vinyl@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.5.3.tgz#b0455b38fc5e0cf30d4325132e461970c2091cde" + integrity sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4= + dependencies: + clone "^1.0.0" + clone-stats "^0.0.1" + replace-ext "0.0.1" + +vinyl@^2.0.0, vinyl@^2.1.0, vinyl@^2.2.0, vinyl@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.1.tgz#23cfb8bbab5ece3803aa2c0a1eb28af7cbba1974" + integrity sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw== + dependencies: + clone "^2.1.1" + clone-buffer "^1.0.0" + clone-stats "^1.0.0" + cloneable-readable "^1.0.0" + remove-trailing-separator "^1.0.1" + replace-ext "^1.0.0" + +vm-browserify@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" + integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== + +w3c-hr-time@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== + dependencies: + browser-process-hrtime "^1.0.0" + +w3c-xmlserializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" + integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== + dependencies: + xml-name-validator "^3.0.0" + +walker@^1.0.7, walker@~1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= + dependencies: + makeerror "1.0.x" + +webidl-conversions@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" + integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== + +webidl-conversions@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" + integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== + +webrtc-adapter@^7.7.0: + version "7.7.0" + resolved "https://registry.yarnpkg.com/webrtc-adapter/-/webrtc-adapter-7.7.0.tgz#e56ff25f925177ac553a7c49323ca4108d2b5f4d" + integrity sha512-7Bp9OBnx642oJRkom1tNAbeJjUadAq2rh5xLL9YXPw5hVyt2h4hHr5bcoPYDs1stp/mZHSPSQA34YISdnr0DBQ== + dependencies: + rtcpeerconnection-shim "^1.2.15" + sdp "^2.12.0" + +websocket-driver@>=0.5.1: + version "0.7.4" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== + dependencies: + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== + +whatwg-encoding@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== + dependencies: + iconv-lite "0.4.24" + +whatwg-mimetype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== + +whatwg-url@^8.0.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.4.0.tgz#50fb9615b05469591d2b2bd6dfaed2942ed72837" + integrity sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^2.0.2" + webidl-conversions "^6.1.0" + +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8= + +which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + +which-typed-array@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.2.tgz#e5f98e56bda93e3dac196b01d47c1156679c00b2" + integrity sha512-KT6okrd1tE6JdZAy3o2VhMoYPh3+J6EMZLyrxBQsZflI1QCZIxMrIYLkosd8Twf+YfknVIHmYQPgJt238p8dnQ== + dependencies: + available-typed-arrays "^1.0.2" + es-abstract "^1.17.5" + foreach "^2.0.5" + function-bind "^1.1.1" + has-symbols "^1.0.1" + is-typed-array "^1.1.3" + +which@1, which@^1.2.14, which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1, which@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + +word-wrap@^1.2.3, word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +write-file-atomic@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + +write@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" + integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== + dependencies: + mkdirp "^0.5.1" + +ws@^7.2.3: + version "7.3.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.1.tgz#d0547bf67f7ce4f12a72dfe31262c68d7dc551c8" + integrity sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA== + +ws@~3.3.1: + version "3.3.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" + integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA== + dependencies: + async-limiter "~1.0.0" + safe-buffer "~5.1.0" + ultron "~1.1.0" + +ws@~6.1.0: + version "6.1.4" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9" + integrity sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA== + dependencies: + async-limiter "~1.0.0" + +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== + +xml@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" + integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= + +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + +xmlhttprequest-ssl@~1.5.4: + version "1.5.5" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" + integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4= + +xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.0, xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= + +y18n@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yargs-parser@5.0.0-security.0: + version "5.0.0-security.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0-security.0.tgz#4ff7271d25f90ac15643b86076a2ab499ec9ee24" + integrity sha512-T69y4Ps64LNesYxeYGYPvfoMTt/7y1XtfpIslUeK4um+9Hu7hlGoRtaDLvdXb7+/tfq4opVa2HRY5xGip022rQ== + dependencies: + camelcase "^3.0.0" + object.assign "^4.1.0" + +yargs-parser@^13.1.1, yargs-parser@^13.1.2: + version "13.1.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" + integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^18.1.2: + version "18.1.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs@13.3.0: + version "13.3.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83" + integrity sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.1" + +yargs@^13.3.2: + version "13.3.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" + integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.2" + +yargs@^15.4.1: + version "15.4.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" + integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== + dependencies: + cliui "^6.0.0" + decamelize "^1.2.0" + find-up "^4.1.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^4.2.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^18.1.2" + +yargs@^7.1.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.1.tgz#67f0ef52e228d4ee0d6311acede8850f53464df6" + integrity sha512-huO4Fr1f9PmiJJdll5kwoS2e4GqzGSsMT3PPMpOwoVkOK8ckqAewMTZyA6LXVQWflleb/Z8oPBEvNsMft0XE+g== + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + 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" + y18n "^3.2.1" + yargs-parser "5.0.0-security.0" + +yeast@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" + integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk=