diff --git a/.vscode/launch.json b/.vscode/launch.json
index b7c8245d2b..a9e017d4c1 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -44,11 +44,13 @@
"type": "node",
"request": "launch",
"name": "Server: Launch",
- "args": ["./build/server.js"],
- "preLaunchTask": "server: build",
+ "args": ["./build/init.js"],
+ "env": {
+ "DEBUG": ""
+ },
"restart": true,
"outFiles": ["./build/*"],
- "envFile": "${workspaceFolder}/Composer/packages/server/.env",
+ "preLaunchTask": "server: build",
"outputCapture": "std",
"cwd": "${workspaceFolder}/Composer/packages/server"
},
@@ -77,9 +79,13 @@
"request": "launch",
"name": "Electron Main Process",
"runtimeExecutable": "${workspaceRoot}/Composer/node_modules/.bin/electron",
+ "windows": {
+ "runtimeExecutable": "${workspaceRoot}/Composer/node_modules/.bin/electron.cmd"
+ },
"args": ["${workspaceRoot}/Composer/packages/electron-server"],
"env": {
- "NODE_ENV": "development"
+ "NODE_ENV": "development",
+ "DEBUG": "composer*"
},
"outputCapture": "std"
},
@@ -92,9 +98,7 @@
"${workspaceRoot}/Composer/node_modules/jest/bin/jest",
"--runInBand"
],
- "args": [
- "${fileBasename}",
- ],
+ "args": ["${fileBasename}"],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"port": 9229
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 04e7393d24..a8f3da49b7 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -5,9 +5,11 @@
"tasks": [
{
"label": "server: build",
- "type": "npm",
- "script": "build",
- "path": "Composer/packages/server/",
+ "type": "shell",
+ "command": "yarn build",
+ "options": {
+ "cwd": "Composer/packages/server"
+ },
"problemMatcher": []
}
]
diff --git a/Composer/package.json b/Composer/package.json
index ca6b7578cd..d130ea2e8d 100644
--- a/Composer/package.json
+++ b/Composer/package.json
@@ -22,7 +22,6 @@
"packages/extensions/*",
"packages/lib",
"packages/lib/*",
- "packages/plugin-loader",
"packages/server",
"packages/test-utils",
"packages/tools",
@@ -38,7 +37,7 @@
"build:test": "yarn workspace @bfc/test-utils build",
"build:lib": "yarn workspace @bfc/libs build:all",
"build:electron": "yarn workspace @bfc/electron-server build",
- "build:extensions": "wsrun -lt -p @bfc/plugin-loader @bfc/intellisense @bfc/extension @bfc/adaptive-form @bfc/adaptive-flow @bfc/ui-plugin-* -c build",
+ "build:extensions": "wsrun -lt -p @bfc/plugin-loader @bfc/intellisense @bfc/extension @bfc/adaptive-form @bfc/adaptive-flow @bfc/ui-plugin-* @bfc/client-plugin-lib -c build",
"build:server": "yarn workspace @bfc/server build",
"build:client": "yarn workspace @bfc/client build",
"build:tools": "yarn workspace @bfc/tools build:all",
diff --git a/Composer/packages/client/.gitignore b/Composer/packages/client/.gitignore
index 567609b123..de820129fc 100644
--- a/Composer/packages/client/.gitignore
+++ b/Composer/packages/client/.gitignore
@@ -1 +1,2 @@
build/
+public/*-bundle.js
diff --git a/Composer/packages/client/config/paths.js b/Composer/packages/client/config/paths.js
index 7346475c97..13b4627e5e 100644
--- a/Composer/packages/client/config/paths.js
+++ b/Composer/packages/client/config/paths.js
@@ -7,7 +7,7 @@ const url = require('url');
// Make sure any symlinks in the project folder are resolved:
// https://github.com/facebook/create-react-app/issues/637
const appDirectory = fs.realpathSync(process.cwd());
-const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
+const resolveApp = (relativePath) => path.resolve(appDirectory, relativePath);
const envPublicUrl = process.env.PUBLIC_URL;
@@ -22,7 +22,7 @@ function ensureSlash(inputPath, needsSlash) {
}
}
-const getPublicUrl = appPackageJson => envPublicUrl || require(appPackageJson).homepage;
+const getPublicUrl = (appPackageJson) => envPublicUrl || require(appPackageJson).homepage;
// We use `PUBLIC_URL` environment variable or "homepage" field to infer
// "public path" at which the app is served.
@@ -52,7 +52,7 @@ const moduleFileExtensions = [
// Resolve file paths in the same order as webpack
const resolveModule = (resolveFn, filePath) => {
- const extension = moduleFileExtensions.find(extension => fs.existsSync(resolveFn(`${filePath}.${extension}`)));
+ const extension = moduleFileExtensions.find((extension) => fs.existsSync(resolveFn(`${filePath}.${extension}`)));
if (extension) {
return resolveFn(`${filePath}.${extension}`);
diff --git a/Composer/packages/client/config/webpack-react-dom.config.js b/Composer/packages/client/config/webpack-react-dom.config.js
new file mode 100644
index 0000000000..4e325e745c
--- /dev/null
+++ b/Composer/packages/client/config/webpack-react-dom.config.js
@@ -0,0 +1,22 @@
+const { resolve } = require('path');
+
+module.exports = {
+ entry: {
+ 'react-dom-bundle': 'react-dom',
+ },
+ mode: 'production',
+ // export react-dom globally under a variable named ReactDOM
+ output: {
+ path: resolve(__dirname, '../public'),
+ library: 'ReactDOM',
+ libraryTarget: 'var',
+ },
+ externals: {
+ // ReactDOM depends on React, but we need this to resolve to the globally-exposed React variable in react-bundle.js (created by webpack-react.config.js).
+ // If we don't do this, ReactDom will bundle its own copy of React and we will have 2 copies which breaks hooks.
+ react: 'React',
+ },
+ resolve: {
+ extensions: ['.js'],
+ },
+};
diff --git a/Composer/packages/client/config/webpack-react.config.js b/Composer/packages/client/config/webpack-react.config.js
new file mode 100644
index 0000000000..711737994a
--- /dev/null
+++ b/Composer/packages/client/config/webpack-react.config.js
@@ -0,0 +1,17 @@
+const { resolve } = require('path');
+
+module.exports = {
+ entry: {
+ 'react-bundle': 'react',
+ },
+ mode: 'production',
+ // export react globally under a variable named React
+ output: {
+ path: resolve(__dirname, '../public'),
+ library: 'React',
+ libraryTarget: 'var',
+ },
+ resolve: {
+ extensions: ['.js'],
+ },
+};
diff --git a/Composer/packages/client/package.json b/Composer/packages/client/package.json
index b1fe205426..e83d49570a 100644
--- a/Composer/packages/client/package.json
+++ b/Composer/packages/client/package.json
@@ -8,8 +8,9 @@
"node": ">=12"
},
"scripts": {
- "start": "node scripts/start.js",
+ "start": "yarn build:react-bundles && node scripts/start.js",
"build": "node --max_old_space_size=4096 scripts/build.js",
+ "build:react-bundles": "webpack --config ./config/webpack-react.config.js && webpack --config ./config/webpack-react-dom.config.js",
"clean": "rimraf build",
"test": "jest",
"lint": "eslint --quiet --ext .js,.jsx,.ts,.tsx ./src ./__tests__",
diff --git a/Composer/packages/client/public/extensionContainer.html b/Composer/packages/client/public/extensionContainer.html
deleted file mode 100644
index 56d4f64b40..0000000000
--- a/Composer/packages/client/public/extensionContainer.html
+++ /dev/null
@@ -1,68 +0,0 @@
-
-
-
-
-
-
-
-
-
-
- React App
-
- <% if (process.env.NODE_ENV === 'production') { %>
- if (__nonce__) { ?>
-
- } ?>
- <% } %>
-
-
-
-
-
-
-
-
diff --git a/Composer/packages/client/public/plugin-host-preload.js b/Composer/packages/client/public/plugin-host-preload.js
new file mode 100644
index 0000000000..688fa7b79f
--- /dev/null
+++ b/Composer/packages/client/public/plugin-host-preload.js
@@ -0,0 +1,29 @@
+// add default doc styles
+if (!document.getElementById('plugin-host-default-styles')) {
+ const styles = document.createElement('style');
+ styles.id = 'plugin-host-default-styles';
+ styles.type = 'text/css';
+ styles.appendChild(
+ document.createTextNode(`
+ html, body { padding: 0; margin: 0; }
+ #plugin-root {
+ display: flex;
+ flex-flow: column nowrap;
+ height: 100%;
+ }
+ `)
+ );
+ document.head.appendChild(styles);
+}
+// add the react mount point
+if (!document.getElementById('plugin-root')) {
+ const root = document.createElement('div');
+ root.id = 'plugin-root';
+ document.body.appendChild(root);
+}
+// initialize the API object
+window.Composer = {};
+// init the render function
+window.Composer['render'] = function (component) {
+ ReactDOM.render(component, document.getElementById('plugin-root'));
+};
diff --git a/Composer/packages/client/src/App.tsx b/Composer/packages/client/src/App.tsx
index 03b44d12f5..59661e7adf 100644
--- a/Composer/packages/client/src/App.tsx
+++ b/Composer/packages/client/src/App.tsx
@@ -1,16 +1,23 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-import React, { Fragment } from 'react';
+import React, { Fragment, useEffect } from 'react';
import { initializeIcons } from 'office-ui-fabric-react/lib/Icons';
+import { useRecoilValue } from 'recoil';
import { Header } from './components/Header';
import { Announcement } from './components/AppComponents/Announcement';
import { MainContainer } from './components/AppComponents/MainContainer';
+import { dispatcherState } from './recoilModel/DispatcherWrapper';
initializeIcons(undefined, { disableWarnings: true });
export const App: React.FC = () => {
+ const { fetchPlugins } = useRecoilValue(dispatcherState);
+ useEffect(() => {
+ fetchPlugins();
+ });
+
return (
diff --git a/Composer/packages/client/src/components/PluginHost/PluginHost.tsx b/Composer/packages/client/src/components/PluginHost/PluginHost.tsx
new file mode 100644
index 0000000000..6908b6e367
--- /dev/null
+++ b/Composer/packages/client/src/components/PluginHost/PluginHost.tsx
@@ -0,0 +1,74 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/** @jsx jsx */
+import { jsx, SerializedStyles } from '@emotion/core';
+import * as React from 'react';
+import { useEffect, useRef } from 'react';
+
+import { PluginAPI } from '../../plugins/api';
+import { PluginType } from '../../plugins/types';
+
+import { iframeStyle } from './styles';
+
+interface PluginHostProps {
+ extraIframeStyles?: SerializedStyles[];
+ pluginName?: string;
+ pluginType?: PluginType;
+}
+
+/** Binds closures around Composer client code to plugin iframe's window object */
+function attachPluginAPI(win: Window, type: PluginType) {
+ const api = { ...PluginAPI[type], ...PluginAPI.auth };
+ for (const method in api) {
+ win.Composer[method] = (...args) => api[method](...args);
+ }
+}
+
+function injectScript(doc: Document, id: string, src: string, async: boolean, onload?: () => any) {
+ if (!doc.getElementById(id)) {
+ const script = document.createElement('script');
+ Object.assign(script, { id, src, async, onload });
+ doc.body.appendChild(script);
+ }
+}
+
+/** Abstraction that will render an iframe injected with all the necessary UI plugin scripts,
+ * and then serve the plugin's client bundle.
+ */
+export const PluginHost: React.FC = (props) => {
+ const targetRef = useRef(null);
+ const { extraIframeStyles = [] } = props;
+
+ useEffect(() => {
+ const { pluginName, pluginType } = props;
+ // renders the plugin's UI inside of the iframe
+ const renderPluginView = async () => {
+ if (pluginName && pluginType) {
+ const iframeWindow = targetRef.current?.contentWindow as Window;
+ const iframeDocument = targetRef.current?.contentDocument as Document;
+
+ // inject the react / react-dom bundles
+ injectScript(iframeDocument, 'react-bundle', '/react-bundle.js', false);
+ injectScript(iframeDocument, 'react-dom-bundle', '/react-dom-bundle.js', false);
+ // // load the preload script to setup the plugin API
+ injectScript(iframeDocument, 'preload-bundle', '/plugin-host-preload.js', false, () => {
+ attachPluginAPI(iframeWindow, pluginType);
+ });
+
+ //load the bundle for the specified plugin
+ const pluginScriptId = `plugin-${pluginType}-${pluginName}`;
+ await new Promise((resolve) => {
+ const cb = () => {
+ resolve();
+ };
+ // If plugin bundles end up being too large and block the client thread due to the load, enable the async flag on this call
+ injectScript(iframeDocument, pluginScriptId, `/api/plugins/${pluginName}/view/${pluginType}`, false, cb);
+ });
+ }
+ };
+ renderPluginView();
+ }, [props.pluginName, props.pluginType, targetRef]);
+
+ return ;
+};
diff --git a/Composer/packages/client/src/components/PluginHost/styles.ts b/Composer/packages/client/src/components/PluginHost/styles.ts
new file mode 100644
index 0000000000..0d5314c988
--- /dev/null
+++ b/Composer/packages/client/src/components/PluginHost/styles.ts
@@ -0,0 +1,10 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+import { css } from '@emotion/core';
+
+export const iframeStyle = css`
+ height: 100%;
+ width: 100%;
+ border: 0;
+`;
diff --git a/Composer/packages/client/src/pages/plugin/pluginPageContainer.tsx b/Composer/packages/client/src/pages/plugin/pluginPageContainer.tsx
new file mode 100644
index 0000000000..662b0ca484
--- /dev/null
+++ b/Composer/packages/client/src/pages/plugin/pluginPageContainer.tsx
@@ -0,0 +1,15 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+import React from 'react';
+import { RouteComponentProps } from '@reach/router';
+
+import { PluginHost } from '../../components/PluginHost/PluginHost';
+
+const PluginPageContainer: React.FC> = (props) => {
+ const { pluginId } = props;
+
+ return ;
+};
+
+export { PluginPageContainer };
diff --git a/Composer/packages/client/src/pages/publish/createPublishTarget.tsx b/Composer/packages/client/src/pages/publish/createPublishTarget.tsx
index 9d411567bb..cc9fe43042 100644
--- a/Composer/packages/client/src/pages/publish/createPublishTarget.tsx
+++ b/Composer/packages/client/src/pages/publish/createPublishTarget.tsx
@@ -7,7 +7,7 @@ import formatMessage from 'format-message';
import { Dropdown, IDropdownOption } from 'office-ui-fabric-react/lib/Dropdown';
import { TextField } from 'office-ui-fabric-react/lib/TextField';
import { DialogFooter } from 'office-ui-fabric-react/lib/Dialog';
-import { Fragment, useState, useMemo } from 'react';
+import { Fragment, useState, useMemo, useEffect } from 'react';
import { PrimaryButton, DefaultButton } from 'office-ui-fabric-react/lib/Button';
import { JsonEditor } from '@bfc/code-editor';
import { useRecoilValue } from 'recoil';
@@ -15,8 +15,10 @@ import { PublishTarget } from '@bfc/shared';
import { PublishType } from '../../recoilModel/types';
import { userSettingsState } from '../../recoilModel';
+import { PluginHost } from '../../components/PluginHost/PluginHost';
+import { PluginAPI } from '../../plugins/api';
-import { label } from './styles';
+import { label, customPublishUISurface } from './styles';
interface CreatePublishTargetProps {
closeDialog: () => void;
@@ -27,10 +29,12 @@ interface CreatePublishTargetProps {
}
const CreatePublishTarget: React.FC = (props) => {
- const [targetType, setTargetType] = useState(props.current?.type);
- const [name, setName] = useState(props.current ? props.current.name : '');
- const [config, setConfig] = useState(props.current ? JSON.parse(props.current.configuration) : undefined);
+ const { current } = props;
+ const [targetType, setTargetType] = useState(current?.type);
+ const [name, setName] = useState(current ? current.name : '');
+ const [config, setConfig] = useState(current ? JSON.parse(current.configuration) : undefined);
const [errorMessage, setErrorMsg] = useState('');
+ const [pluginConfigIsValid, setPluginConfigIsValid] = useState(false);
const userSettings = useRecoilValue(userSettingsState);
const targetTypes = useMemo(() => {
@@ -69,27 +73,68 @@ const CreatePublishTarget: React.FC = (props) => {
return targetType ? props.types.find((t) => t.name === targetType)?.schema : undefined;
}, [props.targets, targetType]);
+ const hasView = useMemo(() => {
+ return targetType ? props.types.find((t) => t.name === targetType)?.hasView : undefined;
+ }, [props.targets, targetType]);
+
const updateName = (e, newName) => {
setErrorMsg('');
setName(newName);
isNameValid(newName);
};
- const isDisable = () => {
- if (!targetType || !name || errorMessage) {
- return true;
- } else {
- return false;
+ const saveDisabled = useMemo(() => {
+ const disabled = !targetType || !name || !!errorMessage;
+ if (hasView) {
+ // plugin config must also be valid
+ return disabled || !pluginConfigIsValid;
}
- };
+ return disabled;
+ }, [errorMessage, name, pluginConfigIsValid, targetType]);
- const submit = async () => {
+ // setup plugin APIs
+ useEffect(() => {
+ PluginAPI.publish.setPublishConfig = (config) => updateConfig(config);
+ PluginAPI.publish.setConfigIsValid = (valid) => setPluginConfigIsValid(valid);
+ PluginAPI.publish.useConfigBeingEdited = () => [current ? JSON.parse(current.configuration) : undefined];
+ }, [current, targetType, name]);
+
+ const submit = async (_e) => {
if (targetType) {
await props.updateSettings(name, targetType, JSON.stringify(config) || '{}');
props.closeDialog();
}
};
+ const publishTargetContent = useMemo(() => {
+ if (hasView && targetType) {
+ // render custom plugin view
+ return (
+
+ );
+ }
+ // render default instruction / schema editor view
+ return (
+
+ {instructions && {instructions}
}
+ {formatMessage('Publish Configuration')}
+
+
+
+ );
+ }, [targetType, instructions, schema, hasView, saveDisabled]);
+
return (
-
+
);
diff --git a/Composer/packages/client/src/pages/publish/styles.ts b/Composer/packages/client/src/pages/publish/styles.ts
index f4c372c28c..d8b32bb160 100644
--- a/Composer/packages/client/src/pages/publish/styles.ts
+++ b/Composer/packages/client/src/pages/publish/styles.ts
@@ -114,3 +114,7 @@ export const targetSelected = css`
font-weight: ${FontWeights.bold};
font-size: ${FontSizes.small};
`;
+
+export const customPublishUISurface = css`
+ min-height: 300px;
+`;
diff --git a/Composer/packages/client/src/pages/setting/SettingsPage.tsx b/Composer/packages/client/src/pages/setting/SettingsPage.tsx
index c7029925d4..febb998495 100644
--- a/Composer/packages/client/src/pages/setting/SettingsPage.tsx
+++ b/Composer/packages/client/src/pages/setting/SettingsPage.tsx
@@ -73,6 +73,7 @@ const SettingPage: React.FC> = () => {
botSettings: formatMessage('Bot Settings'),
appSettings: formatMessage('Application Settings'),
runtime: formatMessage('Runtime Config'),
+ plugins: formatMessage('Plugins'),
about: formatMessage('About'),
};
@@ -85,12 +86,8 @@ const SettingPage: React.FC> = () => {
},
{ id: 'application', name: settingLabels.appSettings, url: getProjectLink('application') },
{ id: 'runtime', name: settingLabels.runtime, url: getProjectLink('runtime', projectId), disabled: !projectId },
+ // { id: 'plugins', name: settingLabels.plugins, url: getProjectLink('plugins') },
{ id: 'about', name: settingLabels.about, url: getProjectLink('about') },
-
- // { key: '/settings/publish', name: settingLabels.publish, url: '' },
-
- // { key: 'services', name: formatMessage('Services') },
- // { key: 'publishing-staging', name: formatMessage('Publishing and staging'), disabled: true },
];
const openDeleteBotModal = async () => {
diff --git a/Composer/packages/client/src/pages/setting/plugins/Plugins.tsx b/Composer/packages/client/src/pages/setting/plugins/Plugins.tsx
new file mode 100644
index 0000000000..71ffc26bf1
--- /dev/null
+++ b/Composer/packages/client/src/pages/setting/plugins/Plugins.tsx
@@ -0,0 +1,229 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/** @jsx jsx */
+import { jsx } from '@emotion/core';
+import React, { useEffect, useState, useCallback } from 'react';
+import { RouteComponentProps } from '@reach/router';
+import {
+ DetailsList,
+ DetailsListLayoutMode,
+ SelectionMode,
+ IColumn,
+ CheckboxVisibility,
+} from 'office-ui-fabric-react/lib/DetailsList';
+import { DefaultButton, PrimaryButton } from 'office-ui-fabric-react/lib/Button';
+import formatMessage from 'format-message';
+import { Dialog, DialogType, DialogFooter } from 'office-ui-fabric-react/lib/Dialog';
+import { TextField } from 'office-ui-fabric-react/lib/TextField';
+import axios from 'axios';
+import { useRecoilValue } from 'recoil';
+
+import { PluginConfig } from '../../../recoilModel/types';
+import { Toolbar, IToolbarItem } from '../../../components/Toolbar';
+import httpClient from '../../../utils/httpUtil';
+import { dispatcherState, pluginsState } from '../../../recoilModel';
+
+const Plugins: React.FC = () => {
+ const { fetchPlugins, togglePlugin, addPlugin, removePlugin } = useRecoilValue(dispatcherState);
+ const plugins = useRecoilValue(pluginsState);
+ const [showNewModal, setShowNewModal] = useState(false);
+ const [pluginName, setPluginName] = useState(null);
+ const [pluginVersion, setPluginVersion] = useState(null);
+ const [matchingPlugins, setMatchingPlugins] = useState([]);
+ const [selectedPlugin, setSelectedPlugin] = useState();
+
+ useEffect(() => {
+ fetchPlugins();
+ }, []);
+
+ useEffect(() => {
+ if (pluginName !== null) {
+ const source = axios.CancelToken.source();
+
+ const timer = setTimeout(() => {
+ httpClient
+ .get(`/plugins/search?q=${pluginName}`, { cancelToken: source.token })
+ .then((res) => {
+ setMatchingPlugins(res.data);
+ })
+ .catch((err) => {
+ if (!axios.isCancel(err)) {
+ console.error(err);
+ }
+ });
+ }, 200);
+
+ return () => {
+ source.cancel('User interruption');
+ clearTimeout(timer);
+ };
+ }
+ }, [pluginName]);
+
+ const installedColumns: IColumn[] = [
+ {
+ key: 'name',
+ name: formatMessage('Name'),
+ minWidth: 100,
+ maxWidth: 150,
+ onRender: (item: PluginConfig) => {
+ return {item.id};
+ },
+ },
+ {
+ key: 'version',
+ name: formatMessage('Version'),
+ minWidth: 30,
+ maxWidth: 100,
+ onRender: (item: PluginConfig) => {
+ return {item.version};
+ },
+ },
+ {
+ key: 'enabled',
+ name: formatMessage('Enabled'),
+ minWidth: 30,
+ maxWidth: 150,
+ onRender: (item: PluginConfig) => {
+ const text = item.enabled ? formatMessage('Disable') : formatMessage('Enable');
+ return (
+ togglePlugin(item.id, !item.enabled)}>
+ {text}
+
+ );
+ },
+ },
+ {
+ key: 'remove',
+ name: formatMessage('Remove'),
+ minWidth: 30,
+ maxWidth: 150,
+ onRender: (item: PluginConfig) => {
+ return (
+ removePlugin(item.id)}>
+ {formatMessage('Remove')}
+
+ );
+ },
+ },
+ ];
+
+ const matchingColumns: IColumn[] = [
+ {
+ key: 'name',
+ name: formatMessage('Name'),
+ minWidth: 100,
+ maxWidth: 150,
+ onRender: (item: any) => {
+ return {item.id};
+ },
+ },
+ {
+ key: 'description',
+ name: formatMessage('Description'),
+ minWidth: 100,
+ maxWidth: 300,
+ isMultiline: true,
+ onRender: (item: any) => {
+ return {item.description}
;
+ },
+ },
+ {
+ key: 'version',
+ name: formatMessage('Version'),
+ minWidth: 30,
+ maxWidth: 100,
+ onRender: (item: any) => {
+ return {item.version};
+ },
+ },
+ {
+ key: 'url',
+ name: formatMessage('Url'),
+ minWidth: 100,
+ maxWidth: 100,
+ onRender: (item: any) => {
+ return item.url ? (
+
+ View on npm
+
+ ) : null;
+ },
+ },
+ ];
+
+ const toolbarItems: IToolbarItem[] = [
+ // TODO (toanzian / abrown): re-enable once remote plugins are supported
+ /*{
+ type: 'action',
+ text: formatMessage('Add'),
+ buttonProps: {
+ iconProps: {
+ iconName: 'Add',
+ },
+ onClick: () => {
+ setShowNewModal(true);
+ },
+ },
+ align: 'left',
+ },*/
+ ];
+
+ const submit = useCallback(() => {
+ if (selectedPlugin && pluginVersion) {
+ addPlugin(selectedPlugin.id, pluginVersion);
+ setShowNewModal(false);
+ setPluginName(null);
+ setPluginVersion(null);
+ setSelectedPlugin(null);
+ }
+ }, [selectedPlugin, pluginVersion]);
+
+ return (
+
+
+
+
+
+ );
+};
+
+export { Plugins };
diff --git a/Composer/packages/client/src/pages/setting/router.tsx b/Composer/packages/client/src/pages/setting/router.tsx
index b6faf195a2..98214295c5 100644
--- a/Composer/packages/client/src/pages/setting/router.tsx
+++ b/Composer/packages/client/src/pages/setting/router.tsx
@@ -12,6 +12,7 @@ import { About } from '../about/About';
import { DialogSettings } from './dialog-settings/DialogSettings';
import { AppSettings } from './app-settings/AppSettings';
import { RuntimeSettings } from './runtime-settings/RuntimeSettings';
+// import { Plugins } from './plugins/Plugins';
export const SettingsRoutes = React.memo(({ projectId }: { projectId: string }) => {
const applicationError = useRecoilValue(applicationErrorState);
@@ -33,6 +34,7 @@ export const SettingsRoutes = React.memo(({ projectId }: { projectId: string })
+ {/* */}
);
diff --git a/Composer/packages/client/src/plugins/api.ts b/Composer/packages/client/src/plugins/api.ts
new file mode 100644
index 0000000000..ab8a560d5b
--- /dev/null
+++ b/Composer/packages/client/src/plugins/api.ts
@@ -0,0 +1,51 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+import { OAuthClient, OAuthOptions } from '../utils/oauthClient';
+
+interface IAPI {
+ auth: AuthAPI;
+ page?: {};
+ publish: PublishAPI;
+ storage?: {};
+}
+
+interface PublishConfig {
+ [key: string]: any;
+}
+
+interface AuthAPI {
+ login: (options: OAuthOptions) => Promise; // returns an id token
+ getAccessToken: (options: OAuthOptions) => Promise; // returns an access token
+}
+
+interface PublishAPI {
+ setConfigIsValid?: (valid: boolean) => void;
+ setPublishConfig?: (config: PublishConfig) => void;
+ useConfigBeingEdited?: (() => PublishConfig[]) | (() => void);
+}
+
+class API implements IAPI {
+ auth: AuthAPI;
+ publish: PublishAPI;
+
+ constructor() {
+ this.auth = {
+ login: (options: OAuthOptions) => {
+ const client = new OAuthClient(options);
+ return client.login();
+ },
+ getAccessToken: (options: OAuthOptions) => {
+ const client = new OAuthClient(options);
+ return client.getTokenSilently();
+ },
+ };
+ this.publish = {
+ setConfigIsValid: undefined,
+ setPublishConfig: undefined,
+ useConfigBeingEdited: undefined,
+ };
+ }
+}
+
+export const PluginAPI = new API();
diff --git a/Composer/packages/client/src/plugins/types.ts b/Composer/packages/client/src/plugins/types.ts
new file mode 100644
index 0000000000..1dfa876955
--- /dev/null
+++ b/Composer/packages/client/src/plugins/types.ts
@@ -0,0 +1,4 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+export type PluginType = 'publish' | 'page' | 'storage' | 'create';
diff --git a/Composer/packages/client/src/recoilModel/atoms/appState.ts b/Composer/packages/client/src/recoilModel/atoms/appState.ts
index 1caacbaf22..949863ab0f 100644
--- a/Composer/packages/client/src/recoilModel/atoms/appState.ts
+++ b/Composer/packages/client/src/recoilModel/atoms/appState.ts
@@ -10,6 +10,7 @@ import {
RuntimeTemplate,
AppUpdateState,
BoilerplateVersion,
+ PluginConfig,
} from '../../recoilModel/types';
import { getUserSettings } from '../utils';
import onboardingStorage from '../../utils/onboardingStorage';
@@ -150,3 +151,8 @@ export const boilerplateVersionState = atom({
updateRequired: false,
},
});
+
+export const pluginsState = atom({
+ key: getFullyQualifiedKey('plugins'),
+ default: [],
+});
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/index.ts b/Composer/packages/client/src/recoilModel/dispatchers/index.ts
index 2b79a13807..aa00541a8c 100644
--- a/Composer/packages/client/src/recoilModel/dispatchers/index.ts
+++ b/Composer/packages/client/src/recoilModel/dispatchers/index.ts
@@ -18,6 +18,7 @@ import { settingsDispatcher } from './setting';
import { skillDispatcher } from './skill';
import { userDispatcher } from './user';
import { multilangDispatcher } from './multilang';
+import { pluginsDispatcher } from './plugins';
const createDispatchers = () => {
return {
@@ -38,6 +39,7 @@ const createDispatchers = () => {
...skillDispatcher(),
...userDispatcher(),
...multilangDispatcher(),
+ ...pluginsDispatcher(),
};
};
diff --git a/Composer/packages/client/src/recoilModel/dispatchers/plugins.ts b/Composer/packages/client/src/recoilModel/dispatchers/plugins.ts
new file mode 100644
index 0000000000..e1af5ad67b
--- /dev/null
+++ b/Composer/packages/client/src/recoilModel/dispatchers/plugins.ts
@@ -0,0 +1,92 @@
+/* eslint-disable react-hooks/rules-of-hooks */
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+import { CallbackInterface, useRecoilCallback } from 'recoil';
+
+import httpClient from '../../utils/httpUtil';
+import { pluginsState } from '../atoms';
+import { PluginConfig } from '../types';
+
+export const pluginsDispatcher = () => {
+ const fetchPlugins = useRecoilCallback((callbackHelpers: CallbackInterface) => async () => {
+ const { set } = callbackHelpers;
+ try {
+ const res = await httpClient.get('/plugins');
+
+ set(pluginsState, res.data);
+ } catch (err) {
+ console.error(err);
+ }
+ });
+
+ const addPlugin = useRecoilCallback(
+ (callbackHelpers: CallbackInterface) => async (pluginName: string, version: string) => {
+ const { set } = callbackHelpers;
+ try {
+ const res = await httpClient.post('/plugins', { name: pluginName, version });
+ const addedPlugin: PluginConfig = res.data;
+
+ set(pluginsState, (plugins) => {
+ if (plugins.find((p) => p.id === addedPlugin.id)) {
+ plugins = plugins.map((p) => {
+ if (p.id === addedPlugin.id) {
+ return addedPlugin;
+ }
+ return p;
+ });
+ } else {
+ plugins.push(addedPlugin);
+ }
+ return plugins;
+ });
+ } catch (err) {
+ console.error(err);
+ }
+ }
+ );
+
+ const removePlugin = useRecoilCallback((callbackHelpers: CallbackInterface) => async (pluginName: string) => {
+ const { set } = callbackHelpers;
+ try {
+ const res = await httpClient.delete('/plugins', { data: { id: pluginName } });
+
+ set(pluginsState, res.data);
+ } catch (err) {
+ console.error(err);
+ }
+ });
+
+ const togglePlugin = useRecoilCallback(
+ (callbackHelpers: CallbackInterface) => async (pluginId: string, enabled: boolean) => {
+ const { set } = callbackHelpers;
+ try {
+ const res = await httpClient.patch('/plugins/toggle', {
+ id: pluginId,
+ enabled: Boolean(enabled),
+ });
+ const toggledPlugin: PluginConfig = res.data;
+
+ set(pluginsState, (plugins) => {
+ return (plugins = plugins.map((p) => {
+ if (p.id === toggledPlugin.id) {
+ // update the toggled plugin
+ return toggledPlugin;
+ }
+ return p;
+ }));
+ });
+ } catch (err) {
+ // do nothing
+ console.error(err);
+ }
+ }
+ );
+
+ return {
+ fetchPlugins,
+ addPlugin,
+ removePlugin,
+ togglePlugin,
+ };
+};
diff --git a/Composer/packages/client/src/recoilModel/types.ts b/Composer/packages/client/src/recoilModel/types.ts
index c9f8d189f8..de39892340 100644
--- a/Composer/packages/client/src/recoilModel/types.ts
+++ b/Composer/packages/client/src/recoilModel/types.ts
@@ -28,6 +28,7 @@ export interface StorageFolder extends File {
export interface PublishType {
name: string;
description: string;
+ hasView?: boolean;
instructions?: string;
schema?: JSONSchema7;
features: {
@@ -38,6 +39,21 @@ export interface PublishType {
};
}
+// TODO: move this definition to a shared spot
+export interface PluginConfig {
+ id: string;
+ name: string;
+ enabled: boolean;
+ version: string;
+ /** Special property only used in the in-memory representation of plugins to flag as a built-in. Not written to disk. */
+ builtIn?: boolean;
+ configuration: object;
+ /** Path where module is installed */
+ path: string;
+ bundles: any; // TODO: needed?
+ contributes: any; // TODO: define this type
+}
+
export interface RuntimeTemplate {
/** internal use key */
key: string;
diff --git a/Composer/packages/client/src/router.tsx b/Composer/packages/client/src/router.tsx
index 59973489d4..42ff6b4b40 100644
--- a/Composer/packages/client/src/router.tsx
+++ b/Composer/packages/client/src/router.tsx
@@ -16,6 +16,7 @@ import { botOpeningState, projectIdState, dispatcherState, schemasState } from '
import { openAlertModal } from './components/Modal/AlertDialog';
import { dialogStyle } from './components/Modal/dialogStyle';
import { LoadingSpinner } from './components/LoadingSpinner';
+import { PluginPageContainer } from './pages/plugin/pluginPageContainer';
const DesignPage = React.lazy(() => import('./pages/design/DesignPage'));
const LUPage = React.lazy(() => import('./pages/language-understanding/LUPage'));
@@ -59,6 +60,7 @@ const Routes = (props) => {
+
diff --git a/Composer/packages/client/src/types/window.d.ts b/Composer/packages/client/src/types/window.d.ts
index 76431e1312..75e2cc6501 100644
--- a/Composer/packages/client/src/types/window.d.ts
+++ b/Composer/packages/client/src/types/window.d.ts
@@ -11,4 +11,9 @@ interface Window {
* Flag that is set on the window object when the client is embedded within Electron.
*/
__IS_ELECTRON__?: boolean;
+
+ /**
+ * Composer UI Extension API
+ */
+ Composer: any;
}
diff --git a/Composer/packages/client/src/utils/hooks.ts b/Composer/packages/client/src/utils/hooks.ts
index 0981b693ce..359b756dc8 100644
--- a/Composer/packages/client/src/utils/hooks.ts
+++ b/Composer/packages/client/src/utils/hooks.ts
@@ -7,7 +7,7 @@ import replace from 'lodash/replace';
import find from 'lodash/find';
import { useRecoilValue } from 'recoil';
-import { projectIdState, designPageLocationState } from './../recoilModel';
+import { projectIdState, designPageLocationState, pluginsState } from './../recoilModel';
import { bottomLinks, topLinks } from './pageLinks';
import routerCache from './routerCache';
import { projectIdCache } from './projectCache';
@@ -24,9 +24,19 @@ export const useLocation = () => {
export const useLinks = () => {
const projectId = useRecoilValue(projectIdState);
const designPageLocation = useRecoilValue(designPageLocationState);
+ const plugins = useRecoilValue(pluginsState);
const openedDialogId = designPageLocation.dialogId || 'Main';
- return { topLinks: topLinks(projectId, openedDialogId), bottomLinks };
+ // add page-contributing plugins
+ const pluginPages = plugins.reduce((pages, p) => {
+ const pageConfig = p.contributes?.views?.page;
+ if (pageConfig) {
+ pages.push({ ...pageConfig, id: p.id });
+ }
+ return pages;
+ }, [] as any[]);
+
+ return { topLinks: topLinks(projectId, openedDialogId, pluginPages), bottomLinks };
};
export const useRouterCache = (to: string) => {
diff --git a/Composer/packages/client/src/utils/oauthClient.ts b/Composer/packages/client/src/utils/oauthClient.ts
new file mode 100644
index 0000000000..370eb1bfee
--- /dev/null
+++ b/Composer/packages/client/src/utils/oauthClient.ts
@@ -0,0 +1,93 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+import { isElectron } from './electronUtil';
+
+export interface OAuthOptions {
+ clientId: string;
+ scopes: string[];
+}
+
+interface OAuthConfig extends OAuthOptions {
+ redirectUri: string;
+}
+
+interface OAuthTokens {
+ accessToken?: string;
+ idToken?: string;
+}
+
+export class OAuthClient {
+ private config: OAuthConfig;
+ private tokens: OAuthTokens;
+ private id: number;
+ private static clientId = 0;
+
+ constructor(config: OAuthOptions) {
+ this.config = { ...config, redirectUri: 'bfcomposer://oauth' };
+ this.tokens = {};
+ // assign an id to the client so we can route responses back to the right one from the main process
+ this.id = OAuthClient.clientId++;
+ }
+
+ /** Logs in the current user and retrieves an id token from Azure */
+ public async login(): Promise {
+ // we need to perform a login request
+ if (isElectron()) {
+ return new Promise((resolve, reject) => {
+ const { ipcRenderer } = window;
+ ipcRenderer.on('oauth-login-complete', (_ev, idToken: string, id: number) => {
+ if (id === this.id) {
+ // make sure the auth request originated from this client instance
+ this.tokens.idToken = idToken;
+ resolve(idToken);
+ }
+ });
+ ipcRenderer.on('oauth-login-error', (_ev, error, id) => {
+ if (id === this.id) {
+ console.error('There was an error while attempting to log the current user in: ', error);
+ reject(error);
+ }
+ });
+ ipcRenderer.send('oauth-start-login', this.config, this.id);
+ // TODO: after some amount of time we should reject
+ });
+ }
+ return Promise.reject('OAuth flow is currently disabled in the Composer web environment.');
+ }
+
+ /**
+ * Retrieves an Azure access token on behalf of the current signed-in user.
+ */
+ public async getTokenSilently(): Promise {
+ if (isElectron()) {
+ if (!this.tokens.idToken) {
+ // login
+ await this.login();
+ }
+
+ const { ipcRenderer } = window;
+ return new Promise((resolve, reject) => {
+ ipcRenderer.on('oauth-get-access-token-complete', (_ev, accessToken: string, id: number) => {
+ if (id === this.id) {
+ // make sure the auth request originated from this client instance
+ this.tokens.accessToken = accessToken;
+ resolve(accessToken);
+ }
+ });
+ ipcRenderer.on('oauth-get-access-token-error', (_ev, error, id) => {
+ if (id === this.id) {
+ console.error('There was an error while attempting to silently get an access token: ', error);
+ reject(error);
+ }
+ });
+ // get an access token using the id token
+ ipcRenderer.send('oauth-get-access-token', this.config, this.tokens.idToken, this.id);
+ // TODO: after some amount of time we should reject
+ });
+ }
+ return Promise.reject('OAuth flow is currently disabled in the Composer web environment.');
+ }
+
+ // TODO: add token caching
+}
diff --git a/Composer/packages/client/src/utils/pageLinks.ts b/Composer/packages/client/src/utils/pageLinks.ts
index b71c27e821..1d90bcef31 100644
--- a/Composer/packages/client/src/utils/pageLinks.ts
+++ b/Composer/packages/client/src/utils/pageLinks.ts
@@ -2,7 +2,11 @@
// Licensed under the MIT License.
import formatMessage from 'format-message';
-export const topLinks = (projectId: string, openedDialogId: string) => {
+export const topLinks = (
+ projectId: string,
+ openedDialogId: string,
+ pluginPages: { id: string; label: string; icon?: string; when?: string }[]
+) => {
const botLoaded = !!projectId;
let links = [
{
@@ -67,6 +71,18 @@ export const topLinks = (projectId: string, openedDialogId: string) => {
links = links.filter((link) => link.to !== '/home');
}
+ if (pluginPages.length > 0) {
+ pluginPages.forEach((p) => {
+ links.push({
+ to: `page/${p.id}`,
+ iconName: p.icon ?? 'StatusCircleQuestionMark',
+ labelName: p.label,
+ exact: true,
+ disabled: false,
+ });
+ });
+ }
+
return links;
};
diff --git a/Composer/packages/electron-server/src/main.ts b/Composer/packages/electron-server/src/main.ts
index 4082227967..579f209f75 100644
--- a/Composer/packages/electron-server/src/main.ts
+++ b/Composer/packages/electron-server/src/main.ts
@@ -18,6 +18,7 @@ import { AppUpdater } from './appUpdater';
import { parseDeepLinkUrl } from './utility/url';
import { composerProtocol } from './constants';
import { initAppMenu } from './appMenu';
+import { getAccessToken, loginAndGetIdToken, OAuthLoginOptions } from './utility/oauthImplicitFlowHelper';
const error = log.extend('error');
let deeplinkUrl = '';
@@ -55,6 +56,8 @@ async function createAppDataDir() {
const localPublishPath: string = join(composerAppDataPath, 'hostedBots');
const azurePublishPath: string = join(composerAppDataPath, 'publishBots');
process.env.COMPOSER_APP_DATA = join(composerAppDataPath, 'data.json'); // path to the actual data file
+ process.env.COMPOSER_EXTENSION_DATA = join(composerAppDataPath, 'extensions.json');
+ process.env.COMPOSER_REMOTE_PLUGINS_DIR = join(composerAppDataPath, 'remote-plugins');
log('creating composer app data path at: ', composerAppDataPath);
@@ -109,13 +112,31 @@ function initializeAppUpdater(settings: AppUpdaterSettings) {
log('App updater initialized.');
}
+function initAuthListeners(window: Electron.BrowserWindow) {
+ ipcMain.on('oauth-start-login', async (_ev, options: OAuthLoginOptions, id: number) => {
+ try {
+ const idToken = await loginAndGetIdToken(options);
+ window.webContents.send('oauth-login-complete', idToken, id);
+ } catch (e) {
+ window.webContents.send('oauth-login-error', e, id);
+ }
+ });
+ ipcMain.on('oauth-get-access-token', async (_ev, options: OAuthLoginOptions, idToken: string, id: number) => {
+ try {
+ const accessToken = await getAccessToken({ ...options, idToken });
+ window.webContents.send('oauth-get-access-token-complete', accessToken, id);
+ } catch (e) {
+ window.webContents.send('oauth-get-access-token-error', e, id);
+ }
+ });
+}
+
async function loadServer() {
- let pluginsDir = ''; // let this be assigned by start() if in development
if (!isDevelopment) {
// only change paths if packaged electron app
const unpackedDir = getUnpackedAsarPath();
process.env.COMPOSER_RUNTIME_FOLDER = join(unpackedDir, 'runtime');
- pluginsDir = join(unpackedDir, 'build', 'plugins');
+ process.env.COMPOSER_BUILTIN_PLUGINS_DIR = join(unpackedDir, 'build', 'plugins');
}
// only create a new data directory if packaged electron app
@@ -125,7 +146,7 @@ async function loadServer() {
log('Starting server...');
const { start } = await import('@bfc/server');
- serverPort = await start(pluginsDir);
+ serverPort = await start();
log(`Server started at port: ${serverPort}`);
}
@@ -137,6 +158,7 @@ async function main() {
if (process.env.COMPOSER_DEV_TOOLS) {
mainWindow.webContents.openDevTools();
}
+ initAuthListeners(mainWindow);
if (isWindows()) {
deeplinkUrl = processArgsForWindows(process.argv);
diff --git a/Composer/packages/electron-server/src/utility/oauthImplicitFlowHelper.ts b/Composer/packages/electron-server/src/utility/oauthImplicitFlowHelper.ts
new file mode 100644
index 0000000000..e8655f868e
--- /dev/null
+++ b/Composer/packages/electron-server/src/utility/oauthImplicitFlowHelper.ts
@@ -0,0 +1,151 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+import { randomBytes } from 'crypto';
+
+import { BrowserWindow } from 'electron';
+
+const composerRedirectUri = 'bfcomposer://oauth';
+const baseUrl = 'https://login.microsoftonline.com/organizations/';
+const implicitEndpoint = 'oauth2/v2.0/authorize';
+
+function parseJwt(token: string) {
+ const base64Payload = token.split('.')[1];
+ const payload = Buffer.from(base64Payload, 'base64');
+ return JSON.parse(payload.toString());
+}
+
+function generateNonce(): string {
+ return randomBytes(32).toString('base64');
+}
+
+function generateState(clientId: string) {
+ const state = {
+ clientId,
+ guid: randomBytes(32).toString('base64'),
+ time: Date.now(),
+ };
+ return JSON.stringify(state);
+}
+
+export interface OAuthLoginOptions {
+ clientId: string;
+ redirectUri: string;
+ scopes?: string[];
+}
+
+export interface OAuthTokenOptions extends OAuthLoginOptions {
+ idToken: string;
+}
+
+function getLoginUrl(options: OAuthLoginOptions): string {
+ const { clientId, redirectUri, scopes = [] } = options;
+ if (scopes.indexOf('openid') === -1) {
+ scopes.push('openid');
+ }
+ if (scopes.indexOf('profile') === -1) {
+ scopes.push('profile');
+ }
+ const params = [
+ `client_id=${encodeURIComponent(clientId)}`,
+ `response_type=id_token`,
+ `redirect_uri=${encodeURIComponent(redirectUri)}`,
+ `scope=${encodeURIComponent(scopes.join(' '))}`,
+ `response_mode=fragment`,
+ `state=${encodeURIComponent(generateState(clientId))}`,
+ `nonce=${encodeURIComponent(generateNonce())}`,
+ ].join('&');
+
+ const url = `${baseUrl}${implicitEndpoint}?${params}`;
+ return url;
+}
+
+export function getAccessTokenUrl(options: OAuthTokenOptions): string {
+ const { clientId, idToken, redirectUri, scopes = [] } = options;
+ const params = [
+ `client_id=${encodeURIComponent(clientId)}`,
+ `response_type=token`,
+ `redirect_uri=${encodeURIComponent(redirectUri)}`,
+ `scope=${encodeURIComponent(scopes.join(' '))}`,
+ `response_mode=fragment`,
+ `state=${encodeURIComponent(generateState(clientId))}`,
+ `nonce=${encodeURIComponent(generateNonce())}`,
+ `prompt=none`,
+ ];
+ const jwt = parseJwt(idToken);
+ if (jwt.preferred_username) {
+ params.push(`login_hint=${encodeURIComponent(jwt.preferred_username)}`);
+ }
+
+ const url = `${baseUrl}${implicitEndpoint}?${params.join('&')}`;
+ return url;
+}
+
+async function createAccessTokenWindow(url: string): Promise {
+ const tokenWindow = new BrowserWindow({ width: 400, height: 600, show: false });
+ const waitingForAccessToken = monitorWindowForQueryParam(tokenWindow, 'access_token');
+ tokenWindow.loadURL(url);
+ return waitingForAccessToken;
+}
+
+async function createLoginWindow(url: string): Promise {
+ const loginWindow = new BrowserWindow({ width: 400, height: 600, show: true });
+ const waitingForIdToken = monitorWindowForQueryParam(loginWindow, 'id_token');
+ loginWindow.loadURL(url);
+ return waitingForIdToken;
+}
+
+/** Will wait until the specified window redirects to a URL starting with bfcomposer://oauth,
+ * and then resolve with the desired parameter value or reject with an error message.
+ *
+ * @param window The Electron browser window to monitor for redirect events
+ * @param queryParam The query string parameter to be ripped off the final URL after all redirects are finished
+ */
+async function monitorWindowForQueryParam(window: BrowserWindow, queryParam: string): Promise {
+ return new Promise((resolve, reject) => {
+ window.webContents.on('will-redirect', (event, redirectUrl) => {
+ if (redirectUrl.startsWith(composerRedirectUri)) {
+ // We have reached the end of the oauth flow; don't actually complete the redirect.
+ // Just rip the desired parameters from the url and close the window.
+ event.preventDefault();
+ const parsedUrl = new URL(redirectUrl.replace('#', '?'));
+ const param = parsedUrl.searchParams.get(queryParam);
+ if (param) {
+ window.close();
+ resolve(param);
+ }
+ const error = parsedUrl.searchParams.get('error');
+ const errorDescription = parsedUrl.searchParams.get('error_description');
+ if (error || errorDescription) {
+ window.close();
+ reject({ error, errorDescription });
+ }
+ reject({ error: `Unknown error retrieving ${param} from OAuth window` });
+ }
+ });
+ });
+}
+
+/**
+ * Logs the user in using the OAuth implicit flow and returns an id token
+ *
+ * @param id Internal id used by Composer to route the OAuth response back to the client that it originated from
+ * @returns An object containing the id token and the id of the OAuth client that originated the request
+ */
+export async function loginAndGetIdToken(options: OAuthLoginOptions): Promise {
+ const loginUrl = getLoginUrl(options);
+ const res = await createLoginWindow(loginUrl);
+ return res;
+}
+
+/**
+ * Uses an id token to request an access token on behalf of the user and returns token
+ *
+ * @param id Internal id used by Composer to route the OAuth response back to the client that it originated from
+ * @returns An object containing the access token and the id of the OAuth client that originated the request
+ */
+export async function getAccessToken(options: OAuthTokenOptions): Promise {
+ const tokenUrl = getAccessTokenUrl(options);
+ const res = await createAccessTokenWindow(tokenUrl);
+ return res;
+}
diff --git a/Composer/packages/electron-server/src/utility/url.ts b/Composer/packages/electron-server/src/utility/url.ts
index a8dbe64ef3..0765c44a89 100644
--- a/Composer/packages/electron-server/src/utility/url.ts
+++ b/Composer/packages/electron-server/src/utility/url.ts
@@ -6,7 +6,7 @@ import lowerCase from 'lodash/lowerCase';
import log from './logger';
const error = log.extend('electron-deeplink-url');
-export const parseDeepLinkUrl = (deeplinkUrl) => {
+export const parseDeepLinkUrl = (deeplinkUrl: string) => {
try {
const convertedUrl = new URL(deeplinkUrl);
const action = lowerCase(convertedUrl.hostname);
diff --git a/Composer/packages/extensions/client-plugin-lib/.gitignore b/Composer/packages/extensions/client-plugin-lib/.gitignore
new file mode 100644
index 0000000000..c3af857904
--- /dev/null
+++ b/Composer/packages/extensions/client-plugin-lib/.gitignore
@@ -0,0 +1 @@
+lib/
diff --git a/Composer/packages/extensions/client-plugin-lib/package.json b/Composer/packages/extensions/client-plugin-lib/package.json
new file mode 100644
index 0000000000..e848da36c3
--- /dev/null
+++ b/Composer/packages/extensions/client-plugin-lib/package.json
@@ -0,0 +1,21 @@
+{
+ "name": "@bfc/client-plugin-lib",
+ "version": "1.0.0",
+ "description": "Composer plugin library to be consumed by the client bundle of a Composer plugin.",
+ "main": "lib/index.js",
+ "license": "MIT",
+ "private": true,
+ "scripts": {
+ "build": "yarn clean && yarn build:ts",
+ "build:ts": "tsc",
+ "clean": "rimraf lib"
+ },
+ "devDependencies": {
+ "@types/react": "16.9.23",
+ "rimraf": "^3.0.2",
+ "typescript": "^3.8.3"
+ },
+ "dependencies": {
+ "debug": "^4.1.1"
+ }
+}
diff --git a/Composer/packages/extensions/client-plugin-lib/src/auth/index.ts b/Composer/packages/extensions/client-plugin-lib/src/auth/index.ts
new file mode 100644
index 0000000000..7acb67114c
--- /dev/null
+++ b/Composer/packages/extensions/client-plugin-lib/src/auth/index.ts
@@ -0,0 +1,18 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+import { ComposerGlobalName } from '../common/constants';
+import { OAuthOptions } from './types';
+
+/** Logs the user into Azure for a given client ID with the provided scopes. Returns an ID token. */
+export function login(options: OAuthOptions): Promise {
+ return window[ComposerGlobalName].login(options);
+}
+
+/** Requests an access token from Azure for a given client ID with the provided scopes.
+ * Returns an access token that can be used to call APIs on behalf of the user.
+ *
+ */
+export function getAccessToken(options: OAuthOptions): Promise {
+ return window[ComposerGlobalName].getAccessToken(options);
+}
diff --git a/Composer/packages/extensions/client-plugin-lib/src/auth/types.ts b/Composer/packages/extensions/client-plugin-lib/src/auth/types.ts
new file mode 100644
index 0000000000..d50d60d864
--- /dev/null
+++ b/Composer/packages/extensions/client-plugin-lib/src/auth/types.ts
@@ -0,0 +1,9 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+export interface OAuthOptions {
+ /** Client ID of the AAD app that the user is authenticating against. */
+ clientId: string;
+ /** List of OAuth scopes that will be granted once the user has authenticated. */
+ scopes: string[];
+}
diff --git a/Composer/packages/extensions/client-plugin-lib/src/common/constants.ts b/Composer/packages/extensions/client-plugin-lib/src/common/constants.ts
new file mode 100644
index 0000000000..1ab2ccc556
--- /dev/null
+++ b/Composer/packages/extensions/client-plugin-lib/src/common/constants.ts
@@ -0,0 +1,5 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+/** The property name on the plugin iframe's window object that the plugin API is bound to */
+export const ComposerGlobalName = 'Composer';
diff --git a/Composer/packages/extensions/client-plugin-lib/src/common/index.ts b/Composer/packages/extensions/client-plugin-lib/src/common/index.ts
new file mode 100644
index 0000000000..ab83bfe736
--- /dev/null
+++ b/Composer/packages/extensions/client-plugin-lib/src/common/index.ts
@@ -0,0 +1,22 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+import { ComposerGlobalName } from './constants';
+
+/** Renders a react component within a Composer plugin surface. */
+export function render(component: React.ReactElement) {
+ window[ComposerGlobalName].render(component);
+}
+
+/** Allows plugin client bundles to make AJAX calls from the server -- avoiding the issue of CORS */
+function fetchProxy(url: string, options: RequestInit) {
+ return fetch(`/api/plugins/proxy/${encodeURIComponent(url)}`, {
+ method: 'POST',
+ body: JSON.stringify(options),
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+}
+
+export { fetchProxy as fetch };
diff --git a/Composer/packages/extensions/client-plugin-lib/src/index.ts b/Composer/packages/extensions/client-plugin-lib/src/index.ts
new file mode 100644
index 0000000000..7cccef9d08
--- /dev/null
+++ b/Composer/packages/extensions/client-plugin-lib/src/index.ts
@@ -0,0 +1,6 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+export * from './auth';
+export * from './common';
+export * from './publish';
diff --git a/Composer/packages/extensions/client-plugin-lib/src/logger.ts b/Composer/packages/extensions/client-plugin-lib/src/logger.ts
new file mode 100644
index 0000000000..7a8b080dd7
--- /dev/null
+++ b/Composer/packages/extensions/client-plugin-lib/src/logger.ts
@@ -0,0 +1,6 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+import debug from 'debug';
+
+export default debug('composer:client-plugin-lib');
diff --git a/Composer/packages/extensions/client-plugin-lib/src/page/index.ts b/Composer/packages/extensions/client-plugin-lib/src/page/index.ts
new file mode 100644
index 0000000000..2c781df33e
--- /dev/null
+++ b/Composer/packages/extensions/client-plugin-lib/src/page/index.ts
@@ -0,0 +1,4 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// TODO: add page plugin APIs here
diff --git a/Composer/packages/extensions/client-plugin-lib/src/publish/index.ts b/Composer/packages/extensions/client-plugin-lib/src/publish/index.ts
new file mode 100644
index 0000000000..ebf6871b39
--- /dev/null
+++ b/Composer/packages/extensions/client-plugin-lib/src/publish/index.ts
@@ -0,0 +1,17 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+import { ComposerGlobalName } from '../common/constants';
+import { PublishConfig } from './types';
+
+export function setPublishConfig(config: PublishConfig) {
+ window[ComposerGlobalName].setPublishConfig(config);
+}
+
+export function setConfigIsValid(valid: boolean) {
+ window[ComposerGlobalName].setConfigIsValid(valid);
+}
+
+export function useConfigBeingEdited(): PublishConfig[] | undefined[] {
+ return window[ComposerGlobalName].useConfigBeingEdited();
+}
diff --git a/Composer/packages/extensions/client-plugin-lib/src/publish/types.ts b/Composer/packages/extensions/client-plugin-lib/src/publish/types.ts
new file mode 100644
index 0000000000..dcf6701080
--- /dev/null
+++ b/Composer/packages/extensions/client-plugin-lib/src/publish/types.ts
@@ -0,0 +1,6 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+export interface PublishConfig {
+ [key: string]: any;
+}
diff --git a/Composer/packages/extensions/client-plugin-lib/tsconfig.json b/Composer/packages/extensions/client-plugin-lib/tsconfig.json
new file mode 100644
index 0000000000..7b759015d1
--- /dev/null
+++ b/Composer/packages/extensions/client-plugin-lib/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "../../../tsconfig.base.json",
+ "compilerOptions": {
+ "outDir": "./lib/",
+ "sourceMap": true,
+ "target": "es6"
+ },
+ "include": ["src/**/*.ts"]
+}
diff --git a/Composer/packages/extensions/plugin-loader/src/index.ts b/Composer/packages/extensions/plugin-loader/src/index.ts
index d920126f17..2abf54ebfa 100644
--- a/Composer/packages/extensions/plugin-loader/src/index.ts
+++ b/Composer/packages/extensions/plugin-loader/src/index.ts
@@ -3,6 +3,7 @@
export { JSONSchema7 } from 'json-schema';
-export * from './composerPluginRegistration';
-export * from './pluginLoader';
-export * from './types';
+export * from './loader';
+export * from './manager';
+export * from './storage';
+export * from './types/types';
diff --git a/Composer/packages/extensions/plugin-loader/src/composerPluginRegistration.ts b/Composer/packages/extensions/plugin-loader/src/loader/composerPluginRegistration.ts
similarity index 98%
rename from Composer/packages/extensions/plugin-loader/src/composerPluginRegistration.ts
rename to Composer/packages/extensions/plugin-loader/src/loader/composerPluginRegistration.ts
index 10975e026c..1297eb2af1 100644
--- a/Composer/packages/extensions/plugin-loader/src/composerPluginRegistration.ts
+++ b/Composer/packages/extensions/plugin-loader/src/loader/composerPluginRegistration.ts
@@ -4,9 +4,10 @@
import { RequestHandler } from 'express-serve-static-core';
import { Debugger } from 'debug';
+import log from '../logger';
+import { PublishPlugin, RuntimeTemplate, BotTemplate } from '../types/types';
+
import { PluginLoader } from './pluginLoader';
-import log from './logger';
-import { PublishPlugin, RuntimeTemplate, BotTemplate } from './types';
export class ComposerPluginRegistration {
public loader: PluginLoader;
@@ -62,6 +63,7 @@ export class ComposerPluginRegistration {
name: plugin.customName || this.name,
description: plugin.customDescription || this.description,
instructions: plugin.instructions,
+ hasView: plugin.hasView,
schema: plugin.schema,
},
methods: plugin,
diff --git a/Composer/packages/extensions/plugin-loader/src/loader/index.ts b/Composer/packages/extensions/plugin-loader/src/loader/index.ts
new file mode 100644
index 0000000000..ae6fcecc77
--- /dev/null
+++ b/Composer/packages/extensions/plugin-loader/src/loader/index.ts
@@ -0,0 +1,5 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+export * from './composerPluginRegistration';
+export * from './pluginLoader';
diff --git a/Composer/packages/extensions/plugin-loader/src/pluginLoader.ts b/Composer/packages/extensions/plugin-loader/src/loader/pluginLoader.ts
similarity index 95%
rename from Composer/packages/extensions/plugin-loader/src/pluginLoader.ts
rename to Composer/packages/extensions/plugin-loader/src/loader/pluginLoader.ts
index b4245309e6..5ccc65929e 100644
--- a/Composer/packages/extensions/plugin-loader/src/pluginLoader.ts
+++ b/Composer/packages/extensions/plugin-loader/src/loader/pluginLoader.ts
@@ -10,22 +10,19 @@ import { pathToRegexp } from 'path-to-regexp';
import glob from 'globby';
import formatMessage from 'format-message';
+import { UserIdentity, ExtensionCollection, RuntimeTemplate, DEFAULT_RUNTIME } from '../types/types';
+import log from '../logger';
+
import { ComposerPluginRegistration } from './composerPluginRegistration';
-import { UserIdentity, ExtensionCollection, RuntimeTemplate, DEFAULT_RUNTIME } from './types';
-import log from './logger';
export class PluginLoader {
private _passport: passport.PassportStatic;
private _webserver: Express | undefined;
- public loginUri: string;
+ public loginUri = '/login';
public extensions: ExtensionCollection;
constructor() {
- // load any plugins present in the default folder
- // noop for now
- this.loginUri = '/login';
-
this.extensions = {
storage: {},
publish: {},
diff --git a/Composer/packages/extensions/plugin-loader/src/manager/index.ts b/Composer/packages/extensions/plugin-loader/src/manager/index.ts
new file mode 100644
index 0000000000..2dfad0d007
--- /dev/null
+++ b/Composer/packages/extensions/plugin-loader/src/manager/index.ts
@@ -0,0 +1,4 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+export * from './manager';
diff --git a/Composer/packages/extensions/plugin-loader/src/manager/manager.ts b/Composer/packages/extensions/plugin-loader/src/manager/manager.ts
new file mode 100644
index 0000000000..b7e5c72a0a
--- /dev/null
+++ b/Composer/packages/extensions/plugin-loader/src/manager/manager.ts
@@ -0,0 +1,305 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+import path from 'path';
+import { spawn } from 'child_process';
+
+import glob from 'globby';
+import { readJson } from 'fs-extra';
+
+import { pluginLoader } from '../loader';
+import logger from '../logger';
+import { ExtensionManifestStore } from '../storage/extensionManifestStore';
+import { ExtensionBundle, PackageJSON, ExtensionMetadata, ExtensionSearchResult } from '../types/extension';
+
+const log = logger.extend('plugins');
+
+/**
+ * Used to safely execute commands that include user input
+ */
+async function runNpm(command: string): Promise<{ stdout: string; stderr: string }> {
+ return new Promise((resolve) => {
+ log('npm %s', command);
+ const cmdArgs = command.split(' ');
+ let stdout = '';
+ let stderr = '';
+
+ const proc = spawn('npm', cmdArgs);
+
+ proc.stdout.on('data', (data) => {
+ stdout += data;
+ });
+
+ proc.stderr.on('data', (data) => {
+ stderr += data;
+ });
+
+ proc.on('close', () => {
+ resolve({ stdout, stderr });
+ });
+ });
+}
+
+function processBundles(pluginPath: string, bundles: ExtensionBundle[]) {
+ return bundles.map((b) => ({
+ ...b,
+ path: path.resolve(pluginPath, b.path),
+ }));
+}
+
+function getExtensionMetadata(extensionPath: string, packageJson: PackageJSON): ExtensionMetadata {
+ return {
+ id: packageJson.name,
+ name: packageJson.composer?.name ?? packageJson.name,
+ version: packageJson.version,
+ enabled: true,
+ path: extensionPath,
+ bundles: processBundles(extensionPath, packageJson.composer?.bundles ?? []),
+ contributes: packageJson.composer?.contributes ?? {},
+ };
+}
+
+class PluginManager {
+ private searchCache = new Map();
+ private _manifest: ExtensionManifestStore | undefined;
+
+ /**
+ * Returns all extensions currently in the extension manifest
+ */
+ public getAll() {
+ const extensions = this.manifest.getExtensions();
+ return Object.keys(extensions).map((extId) => extensions[extId]);
+ }
+
+ /**
+ * Returns the extension manifest entry for the specified extension ID
+ * @param id Id of the extension to search for
+ */
+ public find(id: string) {
+ return this.manifest.getExtensions()[id];
+ }
+
+ /**
+ * Installs a remote plugin via NPM
+ * @param name The name of the plugin to install
+ * @param version The version of the plugin to install
+ */
+ public async installRemote(name: string, version?: string) {
+ const packageNameAndVersion = version ? `${name}@${version}` : name;
+ const cmd = `install --no-audit --prefix ${this.remotePluginsDir} ${packageNameAndVersion}`;
+ log('Installing %s@%s to %s', name, version, this.remotePluginsDir);
+
+ const { stdout } = await runNpm(cmd);
+
+ log('%s', stdout);
+
+ const packageJson = await this.getPackageJson(name);
+
+ if (packageJson) {
+ const pluginPath = path.resolve(this.remotePluginsDir, 'node_modules', name);
+ this.manifest.updateExtensionConfig(name, getExtensionMetadata(pluginPath, packageJson));
+ } else {
+ throw new Error(`Unable to install ${packageNameAndVersion}`);
+ }
+ }
+
+ /**
+ * Loads all the plugins that are checked into the Composer project (1P plugins)
+ */
+ public async loadBuiltinPlugins() {
+ log('Loading inherent plugins from: ', this.builtinPluginsDir);
+
+ // get all plugins with a package.json in the plugins dir
+ const plugins = await glob('*/package.json', { cwd: this.builtinPluginsDir, dot: true });
+ for (const p in plugins) {
+ // go through each plugin, make sure to add it to the manager store then load it as usual
+ const pluginPackageJsonPath = plugins[p];
+ const fullPath = path.join(this.builtinPluginsDir, pluginPackageJsonPath);
+ const pluginInstallPath = path.dirname(fullPath);
+ const packageJson = (await readJson(fullPath)) as PackageJSON;
+ if (packageJson && (!!packageJson.composer || !!packageJson.extendsComposer)) {
+ const metadata = getExtensionMetadata(pluginInstallPath, packageJson);
+ this.manifest.updateExtensionConfig(packageJson.name, {
+ ...metadata,
+ builtIn: true,
+ });
+ await pluginLoader.loadPluginFromFile(fullPath);
+ }
+ }
+ }
+
+ /**
+ * Loads all installed remote plugins
+ * TODO (toanzian / abrown): Needs to be implemented
+ */
+ public async loadRemotePlugins() {
+ // should perform the same function as loadBuiltInPlugins but from the
+ // location that remote / 3P plugins are installed
+ }
+
+ public async load(id: string) {
+ try {
+ const modulePath = require.resolve(id, {
+ paths: [`${this.remotePluginsDir}/node_modules`],
+ });
+ // eslint-disable-next-line @typescript-eslint/no-var-requires, security/detect-non-literal-require
+ const plugin = require(modulePath);
+ log('got plugin: ', plugin);
+
+ if (!plugin) {
+ throw new Error('Plugin not found');
+ }
+
+ await pluginLoader.loadPlugin(id, '', plugin);
+ } catch (err) {
+ log('Unable to load plugin `%s`', id);
+ log('%O', err);
+ await this.remove(id);
+ throw err;
+ }
+ }
+
+ /**
+ * Enables a plugin
+ * @param id Id of the plugin to be enabled
+ */
+ public async enable(id: string) {
+ this.manifest.updateExtensionConfig(id, { enabled: true });
+
+ // re-load plugin
+ }
+
+ /**
+ * Disables a plugin
+ * @param id Id of the plugin to be disabled
+ */
+ public async disable(id: string) {
+ this.manifest.updateExtensionConfig(id, { enabled: false });
+
+ // tear down plugin?
+ }
+
+ /**
+ * Removes a remote plugin via NPM
+ * @param id Id of the plugin to be removed
+ */
+ public async remove(id: string) {
+ const cmd = `uninstall --no-audit --prefix ${this.remotePluginsDir} ${id}`;
+ log('Removing %s', id);
+
+ const { stdout } = await runNpm(cmd);
+
+ log('%s', stdout);
+
+ this.manifest.removeExtension(id);
+ }
+
+ /**
+ * Searches for a plugin via NPM's search function
+ * @param query The search query
+ */
+ public async search(query: string) {
+ const cmd = `search --json keywords:botframework-composer ${query}`;
+
+ const { stdout } = await runNpm(cmd);
+
+ try {
+ const result = JSON.parse(stdout);
+ if (Array.isArray(result)) {
+ result.forEach((searchResult) => {
+ const { name, keywords = [], version, description, links } = searchResult;
+ if (keywords.includes('botframework-composer')) {
+ const url = links?.npm ?? '';
+ this.searchCache.set(name, {
+ id: name,
+ version,
+ description,
+ keywords,
+ url,
+ });
+ }
+ });
+ }
+ } catch (err) {
+ log('%O', err);
+ }
+
+ return Array.from(this.searchCache.values());
+ }
+
+ /**
+ * Returns a list of all of an extension's bundles
+ * @param id The ID of the extension for which we will fetch the list of bundles
+ */
+ public async getAllBundles(id: string) {
+ const info = this.find(id);
+
+ if (!info) {
+ throw new Error('plugin not found');
+ }
+
+ return info.bundles ?? [];
+ }
+
+ /**
+ * Returns a specific bundle for an extension
+ * @param id The id of the desired extension
+ * @param bundleId The id of the desired extension's bundle
+ */
+ public getBundle(id: string, bundleId: string): string | null {
+ const info = this.find(id);
+
+ if (!info) {
+ throw new Error('plugin not found');
+ }
+
+ const bundle = info.bundles.find((b) => b.id === bundleId);
+
+ if (!bundle) {
+ throw new Error('bundle not found');
+ }
+
+ return bundle.path;
+ }
+
+ private async getPackageJson(id: string): Promise {
+ try {
+ const pluginPackagePath = path.resolve(this.remotePluginsDir, 'node_modules', id, 'package.json');
+ log('fetching package.json for %s at %s', id, pluginPackagePath);
+ const packageJson = await readJson(pluginPackagePath);
+ return packageJson as PackageJSON;
+ } catch (err) {
+ log('Error getting package json for %s', id);
+ console.error(err);
+ }
+ }
+
+ private get manifest() {
+ if (this._manifest) {
+ return this._manifest;
+ }
+
+ this._manifest = new ExtensionManifestStore();
+ return this._manifest;
+ }
+
+ private get builtinPluginsDir() {
+ if (!process.env.COMPOSER_BUILTIN_PLUGINS_DIR) {
+ throw new Error('COMPOSER_BUILTIN_PLUGINS_DIR must be set.');
+ }
+
+ return process.env.COMPOSER_BUILTIN_PLUGINS_DIR;
+ }
+
+ private get remotePluginsDir() {
+ if (!process.env.COMPOSER_REMOTE_PLUGINS_DIR) {
+ throw new Error('COMPOSER_REMOTE_PLUGINS_DIR must be set.');
+ }
+
+ return process.env.COMPOSER_REMOTE_PLUGINS_DIR;
+ }
+}
+
+const manager = new PluginManager();
+
+export { manager as PluginManager };
diff --git a/Composer/packages/extensions/plugin-loader/src/storage/extensionManifestStore.ts b/Composer/packages/extensions/plugin-loader/src/storage/extensionManifestStore.ts
new file mode 100644
index 0000000000..99f2079dee
--- /dev/null
+++ b/Composer/packages/extensions/plugin-loader/src/storage/extensionManifestStore.ts
@@ -0,0 +1,86 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+import { existsSync, writeJsonSync, readJsonSync } from 'fs-extra';
+
+import logger from '../logger';
+import { ExtensionMap, ExtensionMetadata } from '../types/extension';
+
+const log = logger.extend('plugins');
+
+export interface ExtensionManifest {
+ extensions: ExtensionMap;
+}
+
+const DEFAULT_MANIFEST: ExtensionManifest = {
+ extensions: {},
+};
+
+function omitBuiltinProperty(key: string, value: string) {
+ if (key && key === 'builtIn') {
+ return undefined;
+ }
+ return value;
+}
+
+/** In-memory representation of extensions.json as well as reads / writes data to disk. */
+export class ExtensionManifestStore {
+ private manifest: ExtensionManifest = DEFAULT_MANIFEST;
+ private manifestPath: string;
+
+ constructor() {
+ this.manifestPath = process.env.COMPOSER_EXTENSION_DATA as string;
+ // create extensions.json if it doesn't exist
+ if (!existsSync(this.manifestPath)) {
+ log('extensions.json does not exist yet. Writing file to path: %s', this.manifestPath);
+ writeJsonSync(this.manifestPath, DEFAULT_MANIFEST, { spaces: 2 });
+ }
+ this.readManifestFromDisk(); // load manifest into memory
+ }
+
+ // load manifest into memory
+ private readManifestFromDisk() {
+ try {
+ const manifest: ExtensionManifest = readJsonSync(this.manifestPath);
+ this.manifest = manifest;
+ } catch (e) {
+ log('Error reading %s: %s', this.manifestPath, e);
+ }
+ }
+
+ // write manifest from memory to disk
+ private writeManifestToDisk() {
+ try {
+ writeJsonSync(this.manifestPath, this.manifest, { replacer: omitBuiltinProperty, spaces: 2 });
+ } catch (e) {
+ log('Error writing %s: %s', this.manifestPath, e);
+ }
+ }
+
+ public getExtensionConfig(id: string) {
+ return this.manifest.extensions[id];
+ }
+
+ public getExtensions() {
+ return this.manifest.extensions;
+ }
+
+ public removeExtension(id: string) {
+ delete this.manifest.extensions[id];
+ // sync changes to disk
+ this.writeManifestToDisk();
+ }
+
+ // update extension config
+ public updateExtensionConfig(id: string, newConfig: Partial) {
+ const currentConfig = this.manifest.extensions[id];
+
+ if (currentConfig) {
+ this.manifest.extensions[id] = Object.assign(currentConfig, newConfig);
+ } else {
+ this.manifest.extensions[id] = Object.assign({} as ExtensionMetadata, newConfig);
+ }
+ // sync changes to disk
+ this.writeManifestToDisk();
+ }
+}
diff --git a/Composer/packages/extensions/plugin-loader/src/storage/index.ts b/Composer/packages/extensions/plugin-loader/src/storage/index.ts
new file mode 100644
index 0000000000..107a3aac66
--- /dev/null
+++ b/Composer/packages/extensions/plugin-loader/src/storage/index.ts
@@ -0,0 +1,4 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+export * from './extensionManifestStore';
diff --git a/Composer/packages/extensions/plugin-loader/src/types/extension.ts b/Composer/packages/extensions/plugin-loader/src/types/extension.ts
new file mode 100644
index 0000000000..c0ae780e5a
--- /dev/null
+++ b/Composer/packages/extensions/plugin-loader/src/types/extension.ts
@@ -0,0 +1,64 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+export type ExtensionContribution = {
+ views?: {
+ page?: {
+ id: string;
+ name: string;
+ icon?: string;
+ when?: string;
+ }[];
+ publish?: {
+ bundleId?: string;
+ };
+ };
+};
+
+export type ExtensionBundle = {
+ id: string;
+ path: string;
+};
+
+export interface ExtensionMetadata {
+ /** name field from package.json */
+ id: string;
+ /** name field from composer object in package.json, defaults to id */
+ name: string;
+ /** currently installed version */
+ version: string;
+ /** enabled or disabled */
+ enabled: boolean;
+ /** path to where module is installed */
+ path: string;
+ /** Special property only used in the in-memory representation of plugins to flag as a built-in. Not written to disk. */
+ builtIn?: boolean;
+ bundles: ExtensionBundle[];
+ contributes: ExtensionContribution;
+}
+
+export interface ExtensionMap {
+ [id: string]: ExtensionMetadata;
+}
+
+/** Info about a plugin returned from an NPM search query */
+export interface ExtensionSearchResult {
+ id: string;
+ keywords: string[];
+ version: string;
+ description: string;
+ url: string;
+}
+
+/** Representation of the properties Composer cares about inside of an extension's package.json */
+export interface PackageJSON {
+ name: string;
+ version: string;
+ description: string;
+ extendsComposer: boolean;
+ composer?: {
+ name?: string;
+ contributes?: ExtensionContribution;
+ bundles?: ExtensionBundle[];
+ };
+}
diff --git a/Composer/packages/extensions/plugin-loader/src/types.ts b/Composer/packages/extensions/plugin-loader/src/types/types.ts
similarity index 97%
rename from Composer/packages/extensions/plugin-loader/src/types.ts
rename to Composer/packages/extensions/plugin-loader/src/types/types.ts
index 5d71c6a8c0..76854b0fbe 100644
--- a/Composer/packages/extensions/plugin-loader/src/types.ts
+++ b/Composer/packages/extensions/plugin-loader/src/types/types.ts
@@ -1,9 +1,11 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
+
import { RequestHandler } from 'express-serve-static-core';
import { JSONSchema7 } from 'json-schema';
import { DialogSetting } from '@bfc/shared';
import { IBotProject } from '@bfc/shared';
+
// TODO: this will be possible when ifilestorage is in a shared module
export interface PublishResult {
@@ -51,6 +53,7 @@ export interface PublishPlugin {
instructions?: string;
customName?: string;
customDescription?: string;
+ hasView: boolean;
[key: string]: any;
}
@@ -113,6 +116,8 @@ export interface ExtensionCollection {
instructions?: string;
/** (Optional) Schema for publishing configuration. */
schema?: JSONSchema7;
+ /** Whether or not the plugin has custom UI to host in the publish surface */
+ hasView: boolean;
};
methods: PublishPlugin;
};
diff --git a/Composer/packages/server/.gitignore b/Composer/packages/server/.gitignore
index d06d964b51..2478a98ff0 100644
--- a/Composer/packages/server/.gitignore
+++ b/Composer/packages/server/.gitignore
@@ -1,3 +1,5 @@
build/
data.json
__tests__/__data__.json
+.composer
+extensions.json
diff --git a/Composer/packages/server/package.json b/Composer/packages/server/package.json
index 3fedf42a9a..17163b7924 100644
--- a/Composer/packages/server/package.json
+++ b/Composer/packages/server/package.json
@@ -22,7 +22,7 @@
},
"author": "",
"nodemonConfig": {
- "exec": "cross-env TS_NODE_FILES=true node --inspect=9228 -r ts-node/register src/init.ts",
+ "exec": "cross-env TS_NODE_FILES=true node -r ts-node/register src/init.ts",
"watch": [
"src"
],
diff --git a/Composer/packages/server/src/controllers/plugins.ts b/Composer/packages/server/src/controllers/plugins.ts
new file mode 100644
index 0000000000..74c9973e94
--- /dev/null
+++ b/Composer/packages/server/src/controllers/plugins.ts
@@ -0,0 +1,147 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+import { Request, Response } from 'express';
+import { PluginManager } from '@bfc/plugin-loader';
+
+interface AddPluginRequest extends Request {
+ body: {
+ name?: string;
+ version?: string;
+ };
+}
+
+interface TogglePluginRequest extends Request {
+ body: {
+ id?: string;
+ enabled?: boolean;
+ };
+}
+
+interface RemovePluginRequest extends Request {
+ body: {
+ id?: string;
+ };
+}
+
+interface SearchPluginsRequest extends Request {
+ query: {
+ q?: string;
+ };
+}
+
+interface PluginViewBundleRequest extends Request {
+ params: {
+ id: string;
+ view: string;
+ };
+}
+
+interface PluginFetchRequest extends Request {
+ body: RequestInit;
+ params: {
+ url: string;
+ };
+}
+
+export async function listPlugins(req: Request, res: Response) {
+ res.json(PluginManager.getAll()); // might need to have this list all enabled plugins ?
+}
+
+export async function addPlugin(req: AddPluginRequest, res: Response) {
+ const { name, version } = req.body;
+
+ if (!name) {
+ res.status(400).send({ error: '`name` is missing from body' });
+ return;
+ }
+
+ await PluginManager.installRemote(name, version);
+ await PluginManager.load(name);
+ res.json(PluginManager.find(name));
+}
+
+export async function togglePlugin(req: TogglePluginRequest, res: Response) {
+ const { id, enabled } = req.body;
+
+ if (!id) {
+ res.status(400).json({ error: '`id` is missing from body' });
+ return;
+ }
+
+ if (!PluginManager.find(id)) {
+ res.status(404).json({ error: `plugin \`${id}\` not found` });
+ return;
+ }
+
+ if (enabled === true) {
+ await PluginManager.enable(id);
+ } else {
+ await PluginManager.disable(id);
+ }
+
+ res.json(PluginManager.find(id));
+}
+
+export async function removePlugin(req: RemovePluginRequest, res: Response) {
+ const { id } = req.body;
+
+ if (!id) {
+ res.status(400).send({ error: '`id` is missing from body' });
+ return;
+ }
+
+ if (!PluginManager.find(id)) {
+ res.status(404).json({ error: `plugin \`${id}\` not found` });
+ return;
+ }
+
+ await PluginManager.remove(id);
+ res.json(PluginManager.getAll());
+}
+
+export async function searchPlugins(req: SearchPluginsRequest, res: Response) {
+ const { q } = req.query;
+
+ const results = await PluginManager.search(q ?? '');
+ res.json(results);
+}
+
+export async function getBundleForView(req: PluginViewBundleRequest, res: Response) {
+ const { id, view } = req.params;
+ const plugin = PluginManager.find(id);
+ const bundleId = plugin.contributes.views?.[view].bundleId as string;
+ const bundle = PluginManager.getBundle(id, bundleId);
+ if (bundle) {
+ res.sendFile(bundle);
+ } else {
+ res.status(404);
+ }
+}
+
+export async function performPluginFetch(req: PluginFetchRequest, res: Response) {
+ const { url } = req.params;
+ const options = req.body;
+ if (!url || !options) {
+ return res.status(400).send('Missing URL or request options.');
+ }
+ try {
+ const response = await fetch(url, options);
+ const contentType = response.headers.get('content-type');
+ if (!response.ok) {
+ throw response;
+ }
+ if (!contentType || !contentType.includes('application/json')) {
+ const text = await response.text();
+ return res.send(text);
+ }
+ const json = await response.json();
+ res.json(json);
+ } catch (e) {
+ let error = e;
+ if (e && e.json) {
+ error = await e.json();
+ }
+ res.status(500).send(error);
+ }
+}
diff --git a/Composer/packages/server/src/controllers/publisher.ts b/Composer/packages/server/src/controllers/publisher.ts
index d36a05f0c0..789d15a319 100644
--- a/Composer/packages/server/src/controllers/publisher.ts
+++ b/Composer/packages/server/src/controllers/publisher.ts
@@ -20,6 +20,7 @@ export const PublishController = {
description: plugin.description,
instructions: plugin.instructions,
schema: plugin.schema,
+ hasView: plugin.hasView,
features: {
history: typeof methods.history === 'function',
publish: typeof methods.publish === 'function',
diff --git a/Composer/packages/server/src/router/api.ts b/Composer/packages/server/src/router/api.ts
index 01bd8c190c..ae74c4c568 100644
--- a/Composer/packages/server/src/router/api.ts
+++ b/Composer/packages/server/src/router/api.ts
@@ -8,6 +8,7 @@ import { StorageController } from '../controllers/storage';
import { PublishController } from '../controllers/publisher';
import { AssetController } from '../controllers/asset';
import { EjectController } from '../controllers/eject';
+import * as PluginsController from '../controllers/plugins';
import { UtilitiesController } from './../controllers/utilities';
@@ -61,6 +62,15 @@ router.get('/assets/projectTemplates', AssetController.getProjTemplates);
//help api
router.get('/utilities/qna/parse', UtilitiesController.getQnaContent);
+// plugins
+router.get('/plugins', PluginsController.listPlugins);
+router.post('/plugins', PluginsController.addPlugin);
+router.delete('/plugins', PluginsController.removePlugin);
+router.patch('/plugins/toggle', PluginsController.togglePlugin);
+router.get('/plugins/search', PluginsController.searchPlugins);
+router.get('/plugins/:id/view/:view', PluginsController.getBundleForView);
+// proxy route for plugins (allows plugin client code to make fetch calls using the Composer server as a proxy -- avoids browser blocking request due to CORS)
+router.post('/plugins/proxy/:url', PluginsController.performPluginFetch);
const ErrorHandler = (handler: RequestHandler) => (req: Request, res: Response, next: NextFunction) => {
Promise.resolve(handler(req, res, next)).catch(next);
diff --git a/Composer/packages/server/src/server.ts b/Composer/packages/server/src/server.ts
index da9b2eff9f..cae89089ce 100644
--- a/Composer/packages/server/src/server.ts
+++ b/Composer/packages/server/src/server.ts
@@ -16,7 +16,7 @@ import { IConnection, createConnection } from 'vscode-languageserver';
import { IntellisenseServer } from '@bfc/intellisense-languageserver';
import { LGServer } from '@bfc/lg-languageserver';
import { LUServer } from '@bfc/lu-languageserver';
-import { pluginLoader } from '@bfc/plugin-loader';
+import { pluginLoader, PluginManager } from '@bfc/plugin-loader';
import chalk from 'chalk';
import { BotProjectService } from './services/project';
@@ -25,11 +25,12 @@ import { apiRouter } from './router/api';
import { BASEURL } from './constants';
import { attachLSPServer } from './utility/attachLSP';
import log from './logger';
+import { setEnvDefault } from './utility/setEnvDefault';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const session = require('express-session');
-export async function start(pluginDir?: string): Promise {
+export async function start(): Promise {
const clientDirectory = path.resolve(require.resolve('@bfc/client'), '..');
const app: Express = express();
app.set('view engine', 'ejs');
@@ -45,9 +46,12 @@ export async function start(pluginDir?: string): Promise {
// make sure plugin has access to our express...
pluginLoader.useExpress(app);
- // load all the plugins that exist in the folder
- pluginDir = pluginDir || path.resolve(__dirname, '../../../plugins');
- await pluginLoader.loadPluginsFromFolder(pluginDir);
+ // load all installed plugins
+ setEnvDefault('COMPOSER_EXTENSION_DATA', path.resolve(__dirname, '../extensions.json'));
+ setEnvDefault('COMPOSER_BUILTIN_PLUGINS_DIR', path.resolve(__dirname, '../../../plugins'));
+ setEnvDefault('COMPOSER_REMOTE_PLUGINS_DIR', path.resolve(__dirname, '../../../.composer'));
+ await PluginManager.loadBuiltinPlugins();
+ // TODO (toanzian / abrown): load 3P plugins
const { login, authorize } = getAuthProvider();
diff --git a/Composer/packages/server/src/settings/env.ts b/Composer/packages/server/src/settings/env.ts
index 6b57662b0c..20cf5a1e9c 100644
--- a/Composer/packages/server/src/settings/env.ts
+++ b/Composer/packages/server/src/settings/env.ts
@@ -31,6 +31,7 @@ if (os.platform() === 'win32') {
console.log(err);
}
}
+
export const diskNames = names;
export const platform = os.platform();
export const environment = process.env.NODE_ENV || 'development';
diff --git a/Composer/packages/server/src/store/store.ts b/Composer/packages/server/src/store/store.ts
index d5eff87fa2..457424861c 100644
--- a/Composer/packages/server/src/store/store.ts
+++ b/Composer/packages/server/src/store/store.ts
@@ -31,7 +31,7 @@ class JsonStore implements KVStore {
private data: any;
private filePath: string;
- get = (key: string, defaultValue?: any): any => {
+ public get(key: string, defaultValue?: T): T {
this.readStore();
if (key in this.data) {
@@ -43,12 +43,12 @@ class JsonStore implements KVStore {
} else {
throw Error(`no such key ${key} in store`);
}
- };
+ }
- set = (key: string, value: any): void => {
+ public set(key: string, value: T): void {
this.data[key] = value;
this.flush();
- };
+ }
flush = () => {
fs.writeFileSync(this.filePath, JSON.stringify(this.data, null, 2) + '\n');
diff --git a/Composer/packages/server/src/utility/setEnvDefault.ts b/Composer/packages/server/src/utility/setEnvDefault.ts
new file mode 100644
index 0000000000..4b894784de
--- /dev/null
+++ b/Composer/packages/server/src/utility/setEnvDefault.ts
@@ -0,0 +1,8 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+export function setEnvDefault(varName: string, value: string) {
+ if (process.env[varName] === undefined) {
+ process.env[varName] = value;
+ }
+}
diff --git a/Composer/plugins/sample-ui-plugin/README.md b/Composer/plugins/sample-ui-plugin/README.md
new file mode 100644
index 0000000000..a39e185054
--- /dev/null
+++ b/Composer/plugins/sample-ui-plugin/README.md
@@ -0,0 +1,225 @@
+# How to Write a Plugin that Hosts Custom UI (React)
+
+## Overview
+
+One aspect of Composer is its extension system which allows developers to write independent JavaScript packages that can be plugged into Composer and call APIs to provide new or modify current functionality within the application.
+
+Each extension will consist of a NodeJS module that will be called by Composer as the initial contact point at which the extension will declare what parts of Composer it will extend.
+
+Additionally, Composer allows these extensions to host custom UI -- in the form of a bundled React application -- at select surfaces we call "contribution points."
+
+
+Below, we will explain how you, as a developer, can author your own extension that hosts custom UI within Composer at one of these contribution points.
+
+## Configuring package.json
+
+The first thing that you need to do when authoring a Composer extension is to configure the `package.json` properly. In order to do this, you will need to fill out the following top-level properties in the `package.json`:
+
+**`extendsComposer`** - boolean
+
+This property must be set to `true` in order for Composer to recognize it as an extension.
+
+---
+
+**`composer`** - object
+
+This property will contain the rest of the configuration options for your Composer extension. This will specify things like what contribution points your extension will host custom UI at, and which bundled JavaScript files (your React applications) to load in order to do so.
+
+In the future, we expect the possibilities of this property to grow and change.
+
+---
+
+**`composer.bundles`** - array
+
+The `composer.bundles` property is an array of objects specifying which bundles your extension will provide to Composer in order to host your custom UI. Each entry in the array will specify an `id` for the bundle, and also a relative `path` to the bundle (relative to your `package.json`).
+
+For example, let's say you have created an extension that will host a custom UI that you have created. You have bundled your React application into a single JavaScript file located at `//dist/bundle.js`. You will now edit your `package.json` file at `//package.json` to include the following:
+
+`package.json`
+```
+{
+ "name": "your-project-name",
+ ...
+ "composer": {
+ "bundles": [
+ {
+ "id": "my-bundle",
+ "path": "./dist/bundle.js"
+ }
+ ]
+ }
+}
+```
+This might not seem very useful by itself, but combined with the `composer.contributes` property, this let's Composer know where to look for your React app's bundle when trying to load your custom UI.
+
+---
+
+**`composer.contributes.views`** - object
+
+The `composer.contributes.views` property is an object that allows you to specify which contribution points inside of Composer you want to display custom UI for.
+
+Each key inside of the `views` property represents one of the contribution points that an extension can provide custom UI for.
+
+The current valid contribution points are: `page` and `publish`. More will be available in the future.
+
+`package.json`
+```
+{
+ "name": "your-project-name",
+ ...
+ "composer": {
+ "views": {
+ "page": {
+ // specify page contribution point configration here
+ },
+ "publish": {
+ // specify publish contribution point configuration here
+ }
+ }
+ }
+}
+```
+
+Each `view.` property will specify a `bundleId` property that correlates to the `id` property of the desired React app bundle to display at that contribution point as specified in the `composer.bundles` array.
+
+Adding on to the example that we used in the `composer.bundles` section:
+
+
+`package.json`
+```
+{
+ "name": "your-project-name",
+ ...
+ "composer": {
+ "bundles": [
+ {
+ "id": "my-bundle",
+ "path": "./dist/bundle.js"
+ }
+ ]
+ "views": {
+ "publish": {
+
+ // telling Composer to display bundled React app at ./dist/bundle.js
+ // inside of the publish contribution point surface
+ "bundleId": "my-bundle"
+ }
+ }
+ }
+}
+```
+
+Depending on the contribution point, the `view.` property might also allow other configuration properties besides `bundleId` that will affect each contribution point differently.
+
+> Look at `/sample-ui-plugin/package.json` as an example
+
+## Bundling Extension Client Code
+
+Currently, Composer only allows the hosting of bundled React applications.
+
+### React
+
+**React** (or ReactJS) is a JavaScript framework that allows developers to build complex UI. You can learn more [here](https://reactjs.org/).
+
+### Bundling
+
+**Bundling** is the process of compiling all the NodeJS modules required by your application into one, or multiple JavaScript files. Some bundling tools even allow your NodeJS modules to be run inside of a browser environment, which is especially useful for client code and front end applications such as a React app.
+
+Composer currently supports a single JavaScript bundle for each contribution point an extension wishes to provide UI for, and this section will cover how to configure Webpack to create such a bundle. Webpack is a popular bundling tool, and you can learn more about it [here](https://webpack.js.org/).
+
+### Webpack Configuration
+
+In order to configure Webpack to create a bundle suitable for Composer, your `webpack.config.js` needs to include a few special options that omit React and ReactDOM from being bundled into your JavaScript file. This might seem counterintuitive, but Composer will provide these two libraries when we host your React app, and it will reduce the overall size of your bundle.
+
+In order to accomplish this, add the following top level property to your configuration:
+
+`webpack.config.js`
+```
+module.exports = {
+ entry: {
+ ...
+ },
+
+ // rest of your config that compiles your app into a bundle
+ ...,
+
+ // omit React & ReactDOM
+ externals: {
+ react: 'React',
+ 'react-dom': 'ReactDOM',
+ }
+};
+```
+
+What this `externals` object does, is instead of pulling React and ReactDOM from `import` or `require` statements, Webpack will modify your compiled JavaScript to instead access these libraries via global variables named `React` and `ReactDOM` that are available in the browser context. These will be provided by Composer when your extension's custom UI is hosted within a contribution point.
+
+> Look at `/sample-ui-plugin/webpack.config.js` as an example
+
+## Registering Extension via NodeJS Module
+
+Finally, for your extension to be registered with Composer, you will need to provide a NodeJS module with an initialize function that can be called by Composer to bootstrap your extension.
+
+As an example, let's create our NodeJS module:
+
+`index.js`
+```
+// this will be called by Composer
+function initialize(registration) {
+ const plugin = {
+ customDescription: 'Publish using custom UI',
+ hasView: true, // we have custom UI to host
+ publish,
+ getStatus,
+ };
+
+ // let Composer know that we are providing our own Publishing plugin
+ registration.addPublishMethod(plugin);
+}
+
+async function getStatus(config, project, user) {
+ // get publish status
+
+ // return result
+}
+
+async function publish(config, project, metadata, user) {
+ // start publish
+
+ // return result
+}
+
+module.exports = {
+ initialize,
+};
+```
+
+The `initialize` function will automatically be called by Composer when it tries to load your extension. You can also export a default function, and Composer will try to call that.
+
+The `initialize` function receives an argument, `registration`, that Composer passes to the extension in order to register certain modifications to functionality. In this case, our extension is adding a publish method, and has specified that we also have custom UI to display by setting the `hasView` property on our `plugin` object to `true`.
+
+The last thing we need to do, is specify this NodeJS module as the entry point inside of our `package.json`:
+
+`package.json`
+```
+{
+ "name": "your-project-name",
+ ...
+ "main": "index.js"
+}
+```
+
+When Composer tries to load your extension, it will use this `main` property to locate the correct file to call.
+
+> Look at `/sample-ui-plugin/src/node/index.ts` as an example
+
+## Sample
+
+To see a working sample in action, just navigate to `/sample-ui-plugin/package.json` in this directory and change the `extendsComposer` property to `true`, and the `composer.contributes.views.page-DISABLED` key to `page`.
+
+Then restart the Composer server.
+
+To see the **publish plugin** in action, open a bot project, select "Publish" in the left nav bar, click "Add a new profile," and select "Publish using custom UI."
+
+To check out the **page plugin**, simply click the question mark icon in the left nav bar of Composer, and it should render a page with a labeled input field.
+
+
diff --git a/Composer/plugins/sample-ui-plugin/package.json b/Composer/plugins/sample-ui-plugin/package.json
new file mode 100644
index 0000000000..96d15d3245
--- /dev/null
+++ b/Composer/plugins/sample-ui-plugin/package.json
@@ -0,0 +1,50 @@
+{
+ "name": "sample-ui-plugin",
+ "version": "1.0.0",
+ "license": "ISC",
+ "scripts": {
+ "build": "yarn clean && yarn build:client && yarn build:node",
+ "build:client": "webpack --config webpack.config.js",
+ "build:node": "tsc --project tsconfig.node.json",
+ "clean": "rimraf dist"
+ },
+ "composer": {
+ "bundles": [
+ {
+ "id": "publish",
+ "path": "dist/publish.js"
+ },
+ {
+ "id": "page",
+ "path": "dist/page.js"
+ }
+ ],
+ "contributes": {
+ "views": {
+ "publish": {
+ "bundleId": "publish"
+ },
+ "page-DISABLED": {
+ "bundleId": "page",
+ "label": "Sample UI Plugin"
+ }
+ }
+ }
+ },
+ "extendsComposer": false,
+ "main": "dist/index.js",
+ "dependencies": {
+ "@bfc/client-plugin-lib": "file:../../packages/extensions/client-plugin-lib",
+ "emotion": "^10.0.27",
+ "react": "^16.13.0",
+ "react-dom": "^16.13.0"
+ },
+ "devDependencies": {
+ "@types/node": "^14.6.2",
+ "rimraf": "^3.0.2",
+ "ts-loader": "^8.0.0",
+ "typescript": "^3.9.6",
+ "webpack": "^4.43.0",
+ "webpack-cli": "^3.3.12"
+ }
+}
diff --git a/Composer/plugins/sample-ui-plugin/src/client/page/index.tsx b/Composer/plugins/sample-ui-plugin/src/client/page/index.tsx
new file mode 100644
index 0000000000..cb13db94c1
--- /dev/null
+++ b/Composer/plugins/sample-ui-plugin/src/client/page/index.tsx
@@ -0,0 +1,35 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+import * as React from 'react';
+import { useCallback, useState } from 'react';
+import { render } from '@bfc/client-plugin-lib';
+import { cx } from 'emotion';
+
+import { label, output, pageRoot, shortTextField, textField } from '../styles';
+
+const Main: React.FC<{}> = (props) => {
+ const [text, setText] = useState('');
+
+ const onInputChange = useCallback((ev) => {
+ setText(ev.target.value);
+ }, []);
+
+ return (
+
+
+
+
{text}
+
+ );
+};
+
+render();
diff --git a/Composer/plugins/sample-ui-plugin/src/client/publish/index.tsx b/Composer/plugins/sample-ui-plugin/src/client/publish/index.tsx
new file mode 100644
index 0000000000..ff60db3a32
--- /dev/null
+++ b/Composer/plugins/sample-ui-plugin/src/client/publish/index.tsx
@@ -0,0 +1,9 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+import * as React from 'react';
+import { render } from '@bfc/client-plugin-lib';
+
+import { Main } from './main';
+
+render();
diff --git a/Composer/plugins/sample-ui-plugin/src/client/publish/main.tsx b/Composer/plugins/sample-ui-plugin/src/client/publish/main.tsx
new file mode 100644
index 0000000000..41ec9543c5
--- /dev/null
+++ b/Composer/plugins/sample-ui-plugin/src/client/publish/main.tsx
@@ -0,0 +1,77 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+import * as React from 'react';
+import { useEffect, useCallback, useState } from 'react';
+import { setConfigIsValid, setPublishConfig, useConfigBeingEdited } from '@bfc/client-plugin-lib';
+
+import { column, label, publishRoot, textField } from '../styles';
+
+export const Main: React.FC<{}> = (props) => {
+ const [configBeingEdited] = useConfigBeingEdited();
+ const [val1, setVal1] = useState(configBeingEdited ? configBeingEdited.val1 : '');
+ const [val2, setVal2] = useState(configBeingEdited ? configBeingEdited.val2 : '');
+ const [val3, setVal3] = useState(configBeingEdited ? configBeingEdited.val3 : '');
+
+ const updateVal1 = useCallback((ev) => {
+ setVal1(ev.target.value);
+ }, []);
+
+ const updateVal2 = useCallback((ev) => {
+ setVal2(ev.target.value);
+ }, []);
+
+ const updateVal3 = useCallback((ev) => {
+ setVal3(ev.target.value);
+ }, []);
+
+ useEffect(() => {
+ setPublishConfig({ val1, val2, val3 });
+ if (val1 && val2 && val3) {
+ setConfigIsValid(true);
+ } else {
+ setConfigIsValid(false);
+ }
+ }, [val1, val2, val3]);
+
+ return (
+
+ );
+};
diff --git a/Composer/plugins/sample-ui-plugin/src/client/styles.ts b/Composer/plugins/sample-ui-plugin/src/client/styles.ts
new file mode 100644
index 0000000000..cfcfe49f77
--- /dev/null
+++ b/Composer/plugins/sample-ui-plugin/src/client/styles.ts
@@ -0,0 +1,71 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+import { css } from 'emotion';
+
+export const publishRoot = css`
+ position: relative;
+ display: flex;
+ flex-flow: column nowrap;
+`;
+
+export const pageRoot = css`
+ display: flex;
+ flex-flow: column nowrap;
+ padding: 25px;
+`;
+
+export const column = css`
+ display: flex;
+ flex-flow: column nowrap;
+`;
+
+// copied from Fluent
+export const textField = css`
+ font-size: 14px;
+ font-weight: 400;
+ box-shadow: none;
+ margin: 0;
+ padding: 0px 8px;
+ box-sizing: border-box;
+ border-radius: 2px;
+ border: 1px solid rgb(96, 94, 92);
+ background: none transparent;
+ color: rgb(50; 49; 48);
+ width: 100%;
+ min-width: 0;
+ text-overflow: ellipsis;
+ outline: 0;
+ height: 32;
+
+ &:focus {
+ border-width: 2px;
+ border-color: rgb(0, 120, 212);
+ }
+`;
+
+// copied from Fluent
+export const label = css`
+ font-family: 'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, Roboto,
+ 'Helvetica Neue', sans-serif;
+ font-size: 14px;
+ font-weight: 600;
+ color: rgb(50, 49, 48);
+ box-sizing: border-box;
+ box-shadow: none;
+ margin: 0;
+ display: block;
+ padding: 5px 0px;
+ overflow-wrap: break-word;
+`;
+
+export const shortTextField = css`
+ width: 250px;
+`;
+
+export const output = css`
+ font-family: 'Segoe UI', 'Segoe UI Web (West European)', 'Segoe UI', -apple-system, BlinkMacSystemFont, Roboto,
+ 'Helvetica Neue', sans-serif;
+ font-size: 14px;
+ font-weight: 400;
+`;
diff --git a/Composer/plugins/sample-ui-plugin/src/node/index.ts b/Composer/plugins/sample-ui-plugin/src/node/index.ts
new file mode 100644
index 0000000000..9ee1d8c42e
--- /dev/null
+++ b/Composer/plugins/sample-ui-plugin/src/node/index.ts
@@ -0,0 +1,42 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+// this will be called by composer
+function initialize(registration) {
+ const plugin = {
+ customDescription: 'Publish using custom UI',
+ hasView: true /** we have custom UI to host */,
+ publish,
+ getStatus,
+ };
+ registration.addPublishMethod(plugin);
+}
+
+async function getStatus(config, project, user) {
+ const response = {
+ status: 200,
+ result: {
+ time: new Date(),
+ message: 'Publish successful.',
+ log: [],
+ },
+ };
+ return response;
+}
+
+async function publish(config, project, metadata, user) {
+ const response = {
+ status: 202,
+ result: {
+ time: new Date(),
+ message: 'Publish accepted.',
+ log: [],
+ comment: metadata.comment,
+ },
+ };
+ return response;
+}
+
+module.exports = {
+ initialize,
+};
diff --git a/Composer/plugins/sample-ui-plugin/tsconfig.json b/Composer/plugins/sample-ui-plugin/tsconfig.json
new file mode 100644
index 0000000000..43030ee21b
--- /dev/null
+++ b/Composer/plugins/sample-ui-plugin/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "compilerOptions": {
+ "alwaysStrict": true,
+ "jsx": "react"
+ },
+ "include": [
+ "src/client/**/*",
+ ],
+ "exclude": [
+ "node_modules",
+ ]
+}
diff --git a/Composer/plugins/sample-ui-plugin/tsconfig.node.json b/Composer/plugins/sample-ui-plugin/tsconfig.node.json
new file mode 100644
index 0000000000..39120ebc55
--- /dev/null
+++ b/Composer/plugins/sample-ui-plugin/tsconfig.node.json
@@ -0,0 +1,9 @@
+{
+ "compilerOptions": {
+ "outDir": "dist",
+ "typeRoots" : ["./node_modules/@types"]
+ },
+ "include": [
+ "src/node/**/*"
+ ]
+}
diff --git a/Composer/plugins/sample-ui-plugin/webpack.config.js b/Composer/plugins/sample-ui-plugin/webpack.config.js
new file mode 100644
index 0000000000..abe57b96c8
--- /dev/null
+++ b/Composer/plugins/sample-ui-plugin/webpack.config.js
@@ -0,0 +1,23 @@
+const { resolve } = require('path');
+
+module.exports = {
+ entry: {
+ page: './src/client/page/index.tsx',
+ publish: './src/client/publish/index.tsx',
+ },
+ mode: 'production',
+ output: {
+ path: resolve(__dirname, 'dist'),
+ },
+ externals: {
+ // expect react & react-dom to be available in the extension host iframe globally under "React" and "ReactDOM" variables
+ react: 'React',
+ 'react-dom': 'ReactDOM',
+ },
+ module: {
+ rules: [{ test: /\.tsx?$/, use: 'ts-loader' }],
+ },
+ resolve: {
+ extensions: ['.js', '.ts', '.tsx'],
+ },
+};
diff --git a/Composer/plugins/sample-ui-plugin/yarn.lock b/Composer/plugins/sample-ui-plugin/yarn.lock
new file mode 100644
index 0000000000..e2885e5dfe
--- /dev/null
+++ b/Composer/plugins/sample-ui-plugin/yarn.lock
@@ -0,0 +1,3031 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@babel/code-frame@^7.0.0":
+ 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/helper-module-imports@^7.0.0":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620"
+ integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==
+ dependencies:
+ "@babel/types" "^7.10.4"
+
+"@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/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/runtime@^7.7.2":
+ version "7.11.2"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736"
+ integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==
+ dependencies:
+ regenerator-runtime "^0.13.4"
+
+"@babel/types@^7.10.4":
+ version "7.11.5"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.5.tgz#d9de577d01252d77c6800cee039ee64faf75662d"
+ integrity sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.10.4"
+ lodash "^4.17.19"
+ to-fast-properties "^2.0.0"
+
+"@bfc/client-plugin-lib@file:../../packages/extensions/client-plugin-lib":
+ version "1.0.0"
+ dependencies:
+ debug "^4.1.1"
+
+"@emotion/cache@^10.0.27":
+ version "10.0.29"
+ resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0"
+ integrity sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==
+ dependencies:
+ "@emotion/sheet" "0.9.4"
+ "@emotion/stylis" "0.8.5"
+ "@emotion/utils" "0.11.3"
+ "@emotion/weak-memoize" "0.2.5"
+
+"@emotion/hash@0.8.0":
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
+ integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
+
+"@emotion/memoize@0.7.4":
+ version "0.7.4"
+ resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb"
+ integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==
+
+"@emotion/serialize@^0.11.15", "@emotion/serialize@^0.11.16":
+ version "0.11.16"
+ resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-0.11.16.tgz#dee05f9e96ad2fb25a5206b6d759b2d1ed3379ad"
+ integrity sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==
+ dependencies:
+ "@emotion/hash" "0.8.0"
+ "@emotion/memoize" "0.7.4"
+ "@emotion/unitless" "0.7.5"
+ "@emotion/utils" "0.11.3"
+ csstype "^2.5.7"
+
+"@emotion/sheet@0.9.4":
+ version "0.9.4"
+ resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-0.9.4.tgz#894374bea39ec30f489bbfc3438192b9774d32e5"
+ integrity sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==
+
+"@emotion/stylis@0.8.5":
+ version "0.8.5"
+ resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04"
+ integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==
+
+"@emotion/unitless@0.7.5":
+ version "0.7.5"
+ resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
+ integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
+
+"@emotion/utils@0.11.3":
+ version "0.11.3"
+ resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-0.11.3.tgz#a759863867befa7e583400d322652a3f44820924"
+ integrity sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==
+
+"@emotion/weak-memoize@0.2.5":
+ version "0.2.5"
+ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46"
+ integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==
+
+"@types/node@^14.6.2":
+ version "14.6.2"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.6.2.tgz#264b44c5a28dfa80198fc2f7b6d3c8a054b9491f"
+ integrity sha512-onlIwbaeqvZyniGPfdw/TEhKIh79pz66L1q06WUQqJLnAb6wbjvOtepLYTGHTqzdXgBYIE3ZdmqHDGsRsbBz7A==
+
+"@types/parse-json@^4.0.0":
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
+ integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
+
+"@webassemblyjs/ast@1.9.0":
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964"
+ integrity sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==
+ dependencies:
+ "@webassemblyjs/helper-module-context" "1.9.0"
+ "@webassemblyjs/helper-wasm-bytecode" "1.9.0"
+ "@webassemblyjs/wast-parser" "1.9.0"
+
+"@webassemblyjs/floating-point-hex-parser@1.9.0":
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz#3c3d3b271bddfc84deb00f71344438311d52ffb4"
+ integrity sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==
+
+"@webassemblyjs/helper-api-error@1.9.0":
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz#203f676e333b96c9da2eeab3ccef33c45928b6a2"
+ integrity sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==
+
+"@webassemblyjs/helper-buffer@1.9.0":
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz#a1442d269c5feb23fcbc9ef759dac3547f29de00"
+ integrity sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==
+
+"@webassemblyjs/helper-code-frame@1.9.0":
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz#647f8892cd2043a82ac0c8c5e75c36f1d9159f27"
+ integrity sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==
+ dependencies:
+ "@webassemblyjs/wast-printer" "1.9.0"
+
+"@webassemblyjs/helper-fsm@1.9.0":
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz#c05256b71244214671f4b08ec108ad63b70eddb8"
+ integrity sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==
+
+"@webassemblyjs/helper-module-context@1.9.0":
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz#25d8884b76839871a08a6c6f806c3979ef712f07"
+ integrity sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==
+ dependencies:
+ "@webassemblyjs/ast" "1.9.0"
+
+"@webassemblyjs/helper-wasm-bytecode@1.9.0":
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz#4fed8beac9b8c14f8c58b70d124d549dd1fe5790"
+ integrity sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==
+
+"@webassemblyjs/helper-wasm-section@1.9.0":
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz#5a4138d5a6292ba18b04c5ae49717e4167965346"
+ integrity sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==
+ dependencies:
+ "@webassemblyjs/ast" "1.9.0"
+ "@webassemblyjs/helper-buffer" "1.9.0"
+ "@webassemblyjs/helper-wasm-bytecode" "1.9.0"
+ "@webassemblyjs/wasm-gen" "1.9.0"
+
+"@webassemblyjs/ieee754@1.9.0":
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz#15c7a0fbaae83fb26143bbacf6d6df1702ad39e4"
+ integrity sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==
+ dependencies:
+ "@xtuc/ieee754" "^1.2.0"
+
+"@webassemblyjs/leb128@1.9.0":
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.9.0.tgz#f19ca0b76a6dc55623a09cffa769e838fa1e1c95"
+ integrity sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==
+ dependencies:
+ "@xtuc/long" "4.2.2"
+
+"@webassemblyjs/utf8@1.9.0":
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.9.0.tgz#04d33b636f78e6a6813227e82402f7637b6229ab"
+ integrity sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==
+
+"@webassemblyjs/wasm-edit@1.9.0":
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz#3fe6d79d3f0f922183aa86002c42dd256cfee9cf"
+ integrity sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==
+ dependencies:
+ "@webassemblyjs/ast" "1.9.0"
+ "@webassemblyjs/helper-buffer" "1.9.0"
+ "@webassemblyjs/helper-wasm-bytecode" "1.9.0"
+ "@webassemblyjs/helper-wasm-section" "1.9.0"
+ "@webassemblyjs/wasm-gen" "1.9.0"
+ "@webassemblyjs/wasm-opt" "1.9.0"
+ "@webassemblyjs/wasm-parser" "1.9.0"
+ "@webassemblyjs/wast-printer" "1.9.0"
+
+"@webassemblyjs/wasm-gen@1.9.0":
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz#50bc70ec68ded8e2763b01a1418bf43491a7a49c"
+ integrity sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==
+ dependencies:
+ "@webassemblyjs/ast" "1.9.0"
+ "@webassemblyjs/helper-wasm-bytecode" "1.9.0"
+ "@webassemblyjs/ieee754" "1.9.0"
+ "@webassemblyjs/leb128" "1.9.0"
+ "@webassemblyjs/utf8" "1.9.0"
+
+"@webassemblyjs/wasm-opt@1.9.0":
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz#2211181e5b31326443cc8112eb9f0b9028721a61"
+ integrity sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==
+ dependencies:
+ "@webassemblyjs/ast" "1.9.0"
+ "@webassemblyjs/helper-buffer" "1.9.0"
+ "@webassemblyjs/wasm-gen" "1.9.0"
+ "@webassemblyjs/wasm-parser" "1.9.0"
+
+"@webassemblyjs/wasm-parser@1.9.0":
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz#9d48e44826df4a6598294aa6c87469d642fff65e"
+ integrity sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==
+ dependencies:
+ "@webassemblyjs/ast" "1.9.0"
+ "@webassemblyjs/helper-api-error" "1.9.0"
+ "@webassemblyjs/helper-wasm-bytecode" "1.9.0"
+ "@webassemblyjs/ieee754" "1.9.0"
+ "@webassemblyjs/leb128" "1.9.0"
+ "@webassemblyjs/utf8" "1.9.0"
+
+"@webassemblyjs/wast-parser@1.9.0":
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz#3031115d79ac5bd261556cecc3fa90a3ef451914"
+ integrity sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==
+ dependencies:
+ "@webassemblyjs/ast" "1.9.0"
+ "@webassemblyjs/floating-point-hex-parser" "1.9.0"
+ "@webassemblyjs/helper-api-error" "1.9.0"
+ "@webassemblyjs/helper-code-frame" "1.9.0"
+ "@webassemblyjs/helper-fsm" "1.9.0"
+ "@xtuc/long" "4.2.2"
+
+"@webassemblyjs/wast-printer@1.9.0":
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz#4935d54c85fef637b00ce9f52377451d00d47899"
+ integrity sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==
+ dependencies:
+ "@webassemblyjs/ast" "1.9.0"
+ "@webassemblyjs/wast-parser" "1.9.0"
+ "@xtuc/long" "4.2.2"
+
+"@xtuc/ieee754@^1.2.0":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
+ integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==
+
+"@xtuc/long@4.2.2":
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
+ integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
+
+acorn@^6.4.1:
+ version "6.4.1"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474"
+ integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==
+
+ajv-errors@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d"
+ integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==
+
+ajv-keywords@^3.1.0, ajv-keywords@^3.4.1:
+ version "3.5.1"
+ resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.1.tgz#b83ca89c5d42d69031f424cad49aada0236c6957"
+ integrity sha512-KWcq3xN8fDjSB+IMoh2VaXVhRI0BBGxoYp3rx7Pkb6z0cFjYR9Q9l4yZqqals0/zsioCmocC5H6UvsGD4MoIBA==
+
+ajv@^6.1.0, ajv@^6.10.2:
+ version "6.12.3"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.3.tgz#18c5af38a111ddeb4f2697bd78d68abc1cabd706"
+ integrity sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==
+ 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"
+
+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-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"
+
+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.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"
+
+aproba@^1.1.1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
+ integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
+
+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-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-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-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=
+
+asn1.js@^4.0.0:
+ version "4.10.1"
+ resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0"
+ integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==
+ dependencies:
+ bn.js "^4.0.0"
+ inherits "^2.0.1"
+ minimalistic-assert "^1.0.0"
+
+assert@^1.1.1:
+ 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=
+
+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==
+
+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==
+
+babel-plugin-emotion@^10.0.27:
+ version "10.0.33"
+ resolved "https://registry.yarnpkg.com/babel-plugin-emotion/-/babel-plugin-emotion-10.0.33.tgz#ce1155dcd1783bbb9286051efee53f4e2be63e03"
+ integrity sha512-bxZbTTGz0AJQDHm8k6Rf3RQJ8tX2scsfsRyKVgAbiUPUNIRtlK+7JxP+TAd1kRLABFxe0CFm2VdK4ePkoA9FxQ==
+ dependencies:
+ "@babel/helper-module-imports" "^7.0.0"
+ "@emotion/hash" "0.8.0"
+ "@emotion/memoize" "0.7.4"
+ "@emotion/serialize" "^0.11.16"
+ babel-plugin-macros "^2.0.0"
+ babel-plugin-syntax-jsx "^6.18.0"
+ convert-source-map "^1.5.0"
+ escape-string-regexp "^1.0.5"
+ find-root "^1.1.0"
+ source-map "^0.5.7"
+
+babel-plugin-macros@^2.0.0:
+ version "2.8.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138"
+ integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==
+ dependencies:
+ "@babel/runtime" "^7.7.2"
+ cosmiconfig "^6.0.0"
+ resolve "^1.12.0"
+
+babel-plugin-syntax-jsx@^6.18.0:
+ version "6.18.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz#0af32a9a6e13ca7a3fd5069e62d7b0f58d0d8946"
+ integrity sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=
+
+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-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==
+
+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"
+
+big.js@^5.2.2:
+ version "5.2.2"
+ resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
+ integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
+
+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"
+
+bluebird@^3.5.5:
+ version "3.7.2"
+ resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
+ integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
+
+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.2"
+ resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.2.tgz#c9686902d3c9a27729f43ab10f9d79c2004da7b0"
+ integrity sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA==
+
+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=
+
+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.0"
+ resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.0.tgz#545d0b1b07e6b2c99211082bf1b12cce7a0b0e11"
+ integrity sha512-hEZC1KEeYuoHRqhGhTy6gWrpJA3ZDjFWv0DE61643ZnOXAKJb3u7yWcrU0mMc9SwAqK1n7myPGndkp0dFG7NFA==
+ dependencies:
+ bn.js "^5.1.1"
+ browserify-rsa "^4.0.1"
+ create-hash "^1.2.0"
+ create-hmac "^1.1.7"
+ elliptic "^6.5.2"
+ inherits "^2.0.4"
+ parse-asn1 "^5.1.5"
+ readable-stream "^3.6.0"
+ safe-buffer "^5.2.0"
+
+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"
+
+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@^4.3.0:
+ version "4.9.2"
+ resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8"
+ integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==
+ dependencies:
+ base64-js "^1.0.2"
+ ieee754 "^1.1.4"
+ isarray "^1.0.0"
+
+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=
+
+cacache@^12.0.2:
+ version "12.0.4"
+ resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c"
+ integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==
+ dependencies:
+ bluebird "^3.5.5"
+ chownr "^1.1.1"
+ figgy-pudding "^3.5.1"
+ glob "^7.1.4"
+ graceful-fs "^4.1.15"
+ infer-owner "^1.0.3"
+ lru-cache "^5.1.1"
+ mississippi "^3.0.0"
+ mkdirp "^0.5.1"
+ move-concurrently "^1.0.1"
+ promise-inflight "^1.0.1"
+ rimraf "^2.6.3"
+ ssri "^6.0.1"
+ unique-filename "^1.1.1"
+ y18n "^4.0.0"
+
+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"
+
+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==
+
+camelcase@^5.0.0:
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
+ integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
+
+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"
+
+chokidar@^2.1.8:
+ 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.0:
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.0.tgz#b30611423ce376357c765b9b8f904b9fba3c0be8"
+ integrity sha512-aXAaho2VJtisB/1fg1+3nlLJqGOuewTzQpd/Tz0yTg2R0e4IGtshYvtjowyEumcBv2z+y4+kc75Mz7j5xJskcQ==
+ 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.4.0"
+ optionalDependencies:
+ fsevents "~2.1.2"
+
+chownr@^1.1.1:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
+ integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
+
+chrome-trace-event@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4"
+ integrity sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==
+ dependencies:
+ tslib "^1.9.0"
+
+cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de"
+ integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==
+ dependencies:
+ inherits "^2.0.1"
+ safe-buffer "^5.0.1"
+
+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"
+
+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"
+
+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-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=
+
+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==
+
+commondir@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
+ integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
+
+component-emitter@^1.2.1:
+ 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==
+
+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.5.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"
+
+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==
+
+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=
+
+convert-source-map@^1.5.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"
+
+copy-concurrently@^1.0.0:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0"
+ integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==
+ dependencies:
+ aproba "^1.1.1"
+ fs-write-stream-atomic "^1.0.8"
+ iferr "^0.1.5"
+ mkdirp "^0.5.1"
+ rimraf "^2.5.4"
+ run-queue "^1.0.0"
+
+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=
+
+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=
+
+cosmiconfig@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982"
+ integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==
+ dependencies:
+ "@types/parse-json" "^4.0.0"
+ import-fresh "^3.1.0"
+ parse-json "^5.0.0"
+ path-type "^4.0.0"
+ yaml "^1.7.2"
+
+create-ecdh@^4.0.0:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff"
+ integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==
+ dependencies:
+ bn.js "^4.1.0"
+ elliptic "^6.0.0"
+
+create-emotion@^10.0.27:
+ version "10.0.27"
+ resolved "https://registry.yarnpkg.com/create-emotion/-/create-emotion-10.0.27.tgz#cb4fa2db750f6ca6f9a001a33fbf1f6c46789503"
+ integrity sha512-fIK73w82HPPn/RsAij7+Zt8eCE8SptcJ3WoRMfxMtjteYxud8GDTKKld7MYwAX2TVhrw29uR1N/bVGxeStHILg==
+ dependencies:
+ "@emotion/cache" "^10.0.27"
+ "@emotion/serialize" "^0.11.15"
+ "@emotion/sheet" "0.9.4"
+ "@emotion/utils" "0.11.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@^6.0.5:
+ 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"
+
+crypto-browserify@^3.11.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"
+
+csstype@^2.5.7:
+ version "2.6.13"
+ resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.13.tgz#a6893015b90e84dd6e85d0e3b442a1e84f2dbe0f"
+ integrity sha512-ul26pfSQTZW8dcOnD2iiJssfXw0gdNVX9IJDH/X3K5DGPfj+fUYe3kB+swUY6BF3oZDxaID3AJt+9/ojSAE05A==
+
+cyclist@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9"
+ integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=
+
+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"
+
+decamelize@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+ integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
+
+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=
+
+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"
+
+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"
+
+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=
+
+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"
+
+domain-browser@^1.1.1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
+ integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==
+
+duplexify@^3.4.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"
+
+elliptic@^6.0.0, elliptic@^6.5.2:
+ 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"
+
+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==
+
+emojis-list@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
+ integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
+
+emotion@^10.0.27:
+ version "10.0.27"
+ resolved "https://registry.yarnpkg.com/emotion/-/emotion-10.0.27.tgz#f9ca5df98630980a23c819a56262560562e5d75e"
+ integrity sha512-2xdDzdWWzue8R8lu4G76uWX5WhyQuzATon9LmNeCy/2BHVC6dsEpfhN1a0qhELgtDVdjyEA6J8Y/VlI5ZnaH0g==
+ dependencies:
+ babel-plugin-emotion "^10.0.27"
+ create-emotion "^10.0.27"
+
+end-of-stream@^1.0.0, end-of-stream@^1.1.0:
+ 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"
+
+enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.0, enhanced-resolve@^4.1.1:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.2.0.tgz#5d43bda4a0fd447cb0ebbe71bef8deff8805ad0d"
+ integrity sha512-S7eiFb/erugyd1rLb6mQ3Vuq+EXHv5cpCkNqqIkYkBgN2QdFnyCZzFBleqwGEx4lgNGYij81BWnCrFNK7vxvjQ==
+ dependencies:
+ graceful-fs "^4.1.2"
+ memory-fs "^0.5.0"
+ tapable "^1.0.0"
+
+errno@^0.1.3, errno@~0.1.7:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
+ integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==
+ dependencies:
+ prr "~1.0.1"
+
+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"
+
+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=
+
+eslint-scope@^4.0.3:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848"
+ integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==
+ dependencies:
+ esrecurse "^4.1.0"
+ estraverse "^4.1.1"
+
+esrecurse@^4.1.0:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf"
+ integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==
+ dependencies:
+ estraverse "^4.1.0"
+
+estraverse@^4.1.0, estraverse@^4.1.1:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
+ integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
+
+events@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/events/-/events-3.1.0.tgz#84279af1b34cb75aa88bf5ff291f6d0bd9b31a59"
+ integrity sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==
+
+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"
+
+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"
+
+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"
+
+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"
+
+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-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==
+
+figgy-pudding@^3.5.1:
+ version "3.5.2"
+ resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e"
+ integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==
+
+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"
+
+find-cache-dir@^2.1.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-root@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
+ integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==
+
+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"
+
+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"
+
+flush-write-stream@^1.0.0:
+ 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"
+
+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=
+
+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"
+
+from2@^2.1.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af"
+ integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=
+ dependencies:
+ inherits "^2.0.1"
+ readable-stream "^2.0.0"
+
+fs-write-stream-atomic@^1.0.8:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9"
+ integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=
+ dependencies:
+ graceful-fs "^4.1.2"
+ iferr "^0.1.5"
+ imurmurhash "^0.1.4"
+ readable-stream "1 || 2"
+
+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.1.3"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e"
+ integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==
+
+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-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=
+
+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.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@^7.1.3, glob@^7.1.4:
+ 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-modules@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780"
+ integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==
+ dependencies:
+ global-prefix "^3.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"
+
+global-prefix@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97"
+ integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==
+ dependencies:
+ ini "^1.3.5"
+ kind-of "^6.0.2"
+ which "^1.3.1"
+
+graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2:
+ version "4.2.4"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
+ integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==
+
+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-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"
+
+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"
+
+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"
+
+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=
+
+ieee754@^1.1.4:
+ version "1.1.13"
+ resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
+ integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==
+
+iferr@^0.1.5:
+ version "0.1.5"
+ resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501"
+ integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE=
+
+import-fresh@^3.1.0:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66"
+ integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ==
+ dependencies:
+ parent-module "^1.0.0"
+ resolve-from "^4.0.0"
+
+import-local@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d"
+ integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==
+ dependencies:
+ pkg-dir "^3.0.0"
+ resolve-cwd "^2.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=
+
+infer-owner@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467"
+ integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==
+
+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.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3:
+ 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, ini@^1.3.5:
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
+ integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
+
+interpret@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
+ integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
+
+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-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.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-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-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-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-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-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-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@^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-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-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=
+
+isarray@1.0.0, 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=
+
+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=
+
+"js-tokens@^3.0.0 || ^4.0.0", 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==
+
+json-parse-better-errors@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
+ integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
+
+json-parse-even-better-errors@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.0.tgz#371873c5ffa44304a6ba12419bcfa95f404ae081"
+ integrity sha512-o3aP+RsWDJZayj1SbHNQAI8x0v3T3SKiGoZlNYfbUP1S3omJQ6i9CnqADqkSPaOAxwua4/1YWx5CM7oiChJt2Q==
+
+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==
+
+json5@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
+ integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
+ dependencies:
+ minimist "^1.2.0"
+
+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:
+ 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==
+
+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=
+
+loader-runner@^2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357"
+ integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==
+
+loader-utils@^1.0.2, loader-utils@^1.2.3, loader-utils@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613"
+ integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==
+ dependencies:
+ big.js "^5.2.2"
+ emojis-list "^3.0.0"
+ json5 "^1.0.1"
+
+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"
+
+lodash@^4.17.19:
+ version "4.17.20"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
+ integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
+
+loose-envify@^1.1.0, loose-envify@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
+ integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
+ dependencies:
+ js-tokens "^3.0.0 || ^4.0.0"
+
+lru-cache@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
+ integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==
+ dependencies:
+ yallist "^3.0.2"
+
+make-dir@^2.0.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"
+
+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-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"
+
+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"
+
+memory-fs@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
+ integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=
+ dependencies:
+ errno "^0.1.3"
+ readable-stream "^2.0.1"
+
+memory-fs@^0.5.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c"
+ integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==
+ dependencies:
+ errno "^0.1.3"
+ readable-stream "^2.0.1"
+
+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.0:
+ 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"
+
+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.4:
+ 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.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==
+
+mississippi@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022"
+ integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==
+ dependencies:
+ concat-stream "^1.5.0"
+ duplexify "^3.4.2"
+ end-of-stream "^1.1.0"
+ flush-write-stream "^1.0.0"
+ from2 "^2.1.0"
+ parallel-transform "^1.1.0"
+ pump "^3.0.0"
+ pumpify "^1.3.3"
+ stream-each "^1.1.0"
+ through2 "^2.0.0"
+
+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@^0.5.1, mkdirp@^0.5.3:
+ 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"
+
+move-concurrently@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
+ integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=
+ dependencies:
+ aproba "^1.1.1"
+ copy-concurrently "^1.0.0"
+ fs-write-stream-atomic "^1.0.8"
+ mkdirp "^0.5.1"
+ rimraf "^2.5.4"
+ run-queue "^1.0.3"
+
+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.2"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
+ integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+
+nan@^2.12.1:
+ version "2.14.1"
+ resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01"
+ integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==
+
+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"
+
+neo-async@^2.5.0, neo-async@^2.6.1:
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
+ integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
+
+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==
+
+node-libs-browser@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425"
+ integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==
+ dependencies:
+ assert "^1.1.1"
+ browserify-zlib "^0.2.0"
+ buffer "^4.3.0"
+ console-browserify "^1.1.0"
+ constants-browserify "^1.0.0"
+ crypto-browserify "^3.11.0"
+ domain-browser "^1.1.1"
+ events "^3.0.0"
+ https-browserify "^1.0.0"
+ os-browserify "^0.3.0"
+ path-browserify "0.0.1"
+ process "^0.11.10"
+ punycode "^1.2.4"
+ querystring-es3 "^0.2.0"
+ readable-stream "^2.3.3"
+ stream-browserify "^2.0.1"
+ stream-http "^2.7.2"
+ string_decoder "^1.0.0"
+ timers-browserify "^2.0.4"
+ tty-browserify "0.0.0"
+ url "^0.11.0"
+ util "^0.11.0"
+ vm-browserify "^1.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==
+
+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-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-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.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"
+
+once@^1.3.0, once@^1.3.1, 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"
+
+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=
+
+p-limit@^2.0.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-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==
+
+parallel-transform@^1.1.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc"
+ integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==
+ dependencies:
+ cyclist "^1.0.1"
+ inherits "^2.0.3"
+ readable-stream "^2.1.5"
+
+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"
+
+parse-asn1@^5.0.0, parse-asn1@^5.1.5:
+ version "5.1.5"
+ resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.5.tgz#003271343da58dc94cace494faef3d2147ecea0e"
+ integrity sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==
+ dependencies:
+ asn1.js "^4.0.0"
+ browserify-aes "^1.0.0"
+ create-hash "^1.1.0"
+ evp_bytestokey "^1.0.0"
+ pbkdf2 "^3.0.3"
+ safe-buffer "^5.1.1"
+
+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-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=
+
+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@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a"
+ integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==
+
+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@^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-is-absolute@^1.0.0:
+ 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.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
+ integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
+
+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-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"
+
+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@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
+ integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
+
+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"
+
+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=
+
+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.10:
+ version "0.11.10"
+ resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
+ integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
+
+promise-inflight@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
+ integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
+
+prop-types@^15.6.2:
+ version "15.7.2"
+ resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
+ integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
+ dependencies:
+ loose-envify "^1.4.0"
+ object-assign "^4.1.1"
+ react-is "^16.8.1"
+
+prr@~1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
+ integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY=
+
+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.3:
+ 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.2.4:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+ integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
+
+punycode@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
+ integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
+
+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, randombytes@^2.1.0:
+ 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"
+
+react-dom@^16.13.0:
+ version "16.13.1"
+ resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.13.1.tgz#c1bd37331a0486c078ee54c4740720993b2e0e7f"
+ integrity sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag==
+ dependencies:
+ loose-envify "^1.1.0"
+ object-assign "^4.1.1"
+ prop-types "^15.6.2"
+ scheduler "^0.19.1"
+
+react-is@^16.8.1:
+ version "16.13.1"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
+ integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
+
+react@^16.13.0:
+ version "16.13.1"
+ resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e"
+ integrity sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==
+ dependencies:
+ loose-envify "^1.1.0"
+ object-assign "^4.1.1"
+ prop-types "^15.6.2"
+
+"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, 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@^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"
+
+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.4.0:
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.4.0.tgz#9fdccdf9e9155805449221ac645e8303ab5b9ada"
+ integrity sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==
+ dependencies:
+ picomatch "^2.2.1"
+
+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==
+
+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"
+
+remove-trailing-separator@^1.0.1:
+ 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=
+
+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@^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==
+
+resolve-cwd@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"
+ integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=
+ dependencies:
+ resolve-from "^3.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@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
+ integrity sha1-six699nWiBvItuZTM17rywoYh0g=
+
+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-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.12.0:
+ version "1.17.0"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444"
+ integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==
+ dependencies:
+ path-parse "^1.0.6"
+
+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==
+
+rimraf@^2.5.4, rimraf@^2.6.3:
+ 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@^3.0.2:
+ version "3.0.2"
+ resolved "https://botbuilder.myget.org/F/botframework-cli/npm/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
+ integrity sha1-8aVAK6YiCtUswSgrrBrjqkn9Bho=
+ 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"
+
+run-queue@^1.0.0, run-queue@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47"
+ integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=
+ dependencies:
+ aproba "^1.1.1"
+
+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-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"
+
+scheduler@^0.19.1:
+ version "0.19.1"
+ resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196"
+ integrity sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==
+ dependencies:
+ loose-envify "^1.1.0"
+ object-assign "^4.1.1"
+
+schema-utils@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770"
+ integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==
+ dependencies:
+ ajv "^6.1.0"
+ ajv-errors "^1.0.0"
+ ajv-keywords "^3.1.0"
+
+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@^6.0.0:
+ version "6.3.0"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
+ integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
+
+serialize-javascript@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-3.1.0.tgz#8bf3a9170712664ef2561b44b691eafe399214ea"
+ integrity sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg==
+ dependencies:
+ randombytes "^2.1.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"
+
+setimmediate@^1.0.4:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
+ integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=
+
+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"
+
+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-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=
+
+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"
+
+source-list-map@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
+ integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
+
+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.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.5.6, source-map@^0.5.7:
+ 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.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+ integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
+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"
+
+ssri@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8"
+ integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==
+ dependencies:
+ figgy-pudding "^3.5.1"
+
+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"
+
+stream-browserify@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b"
+ integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==
+ dependencies:
+ inherits "~2.0.1"
+ readable-stream "^2.0.2"
+
+stream-each@^1.1.0:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae"
+ integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==
+ dependencies:
+ end-of-stream "^1.1.0"
+ stream-shift "^1.0.0"
+
+stream-http@^2.7.2:
+ version "2.8.3"
+ resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc"
+ integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==
+ dependencies:
+ builtin-status-codes "^3.0.0"
+ inherits "^2.0.1"
+ readable-stream "^2.3.6"
+ to-arraybuffer "^1.0.0"
+ xtend "^4.0.0"
+
+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==
+
+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_decoder@^1.0.0, 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@^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"
+
+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"
+
+tapable@^1.0.0, tapable@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
+ integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
+
+terser-webpack-plugin@^1.4.3:
+ version "1.4.4"
+ resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.4.tgz#2c63544347324baafa9a56baaddf1634c8abfc2f"
+ integrity sha512-U4mACBHIegmfoEe5fdongHESNJWqsGU+W0S/9+BmYGVQDw1+c2Ow05TpMhxjPK1sRb7cuYq1BPl1e5YHJMTCqA==
+ dependencies:
+ cacache "^12.0.2"
+ find-cache-dir "^2.1.0"
+ is-wsl "^1.1.0"
+ schema-utils "^1.0.0"
+ serialize-javascript "^3.1.0"
+ source-map "^0.6.1"
+ terser "^4.1.2"
+ webpack-sources "^1.4.0"
+ worker-farm "^1.7.0"
+
+terser@^4.1.2:
+ 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"
+
+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"
+
+timers-browserify@^2.0.4:
+ version "2.0.11"
+ resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.11.tgz#800b1f3eee272e5bc53ee465a04d0e804c31211f"
+ integrity sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==
+ dependencies:
+ setimmediate "^1.0.4"
+
+to-arraybuffer@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
+ integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=
+
+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"
+
+ts-loader@^8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-8.0.0.tgz#faf4b1617dcc4a24c2925d92c5b19e9c6621064d"
+ integrity sha512-giEW167rtK1V6eX/DnXEtOgcawwoIp6hqznqYNNSmraUZOq36zMhwBq12JMlYhxf50BC58bscsTSKKtE42zAuw==
+ dependencies:
+ chalk "^2.3.0"
+ enhanced-resolve "^4.0.0"
+ loader-utils "^1.0.2"
+ micromatch "^4.0.0"
+ semver "^6.0.0"
+
+tslib@^1.9.0:
+ version "1.13.0"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
+ integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
+
+tty-browserify@0.0.0:
+ version "0.0.0"
+ resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
+ integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=
+
+typedarray@^0.0.6:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
+ integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
+
+typescript@^3.9.6:
+ version "3.9.6"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.6.tgz#8f3e0198a34c3ae17091b35571d3afd31999365a"
+ integrity sha512-Pspx3oKAPJtjNwE92YS05HQoY7z2SFyOpHo9MqJor3BXAGNaPUs83CuVp9VISFkSjyRfiTpmKuAYGJB7S7hOxw==
+
+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"
+
+unique-filename@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230"
+ integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==
+ dependencies:
+ unique-slug "^2.0.0"
+
+unique-slug@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c"
+ integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==
+ dependencies:
+ imurmurhash "^0.1.4"
+
+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==
+
+uri-js@^4.2.2:
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
+ integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
+ 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.11.0:
+ version "0.11.1"
+ resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61"
+ integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==
+ dependencies:
+ inherits "2.0.3"
+
+v8-compile-cache@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745"
+ integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==
+
+vm-browserify@^1.0.1:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
+ integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
+
+watchpack-chokidar2@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz#9948a1866cbbd6cb824dea13a7ed691f6c8ddff0"
+ integrity sha512-9TyfOyN/zLUbA288wZ8IsMZ+6cbzvsNyEzSBp6e/zkifi6xxbl8SmQ/CxQq32k8NNqrdVEVUVSEf56L4rQ/ZxA==
+ dependencies:
+ chokidar "^2.1.8"
+
+watchpack@^1.6.1:
+ version "1.7.2"
+ resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.2.tgz#c02e4d4d49913c3e7e122c3325365af9d331e9aa"
+ integrity sha512-ymVbbQP40MFTp+cNMvpyBpBtygHnPzPkHqoIwRRj/0B8KhqQwV8LaKjtbaxF2lK4vl8zN9wCxS46IFCU5K4W0g==
+ dependencies:
+ graceful-fs "^4.1.2"
+ neo-async "^2.5.0"
+ optionalDependencies:
+ chokidar "^3.4.0"
+ watchpack-chokidar2 "^2.0.0"
+
+webpack-cli@^3.3.12:
+ version "3.3.12"
+ resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.12.tgz#94e9ada081453cd0aa609c99e500012fd3ad2d4a"
+ integrity sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag==
+ dependencies:
+ chalk "^2.4.2"
+ cross-spawn "^6.0.5"
+ enhanced-resolve "^4.1.1"
+ findup-sync "^3.0.0"
+ global-modules "^2.0.0"
+ import-local "^2.0.0"
+ interpret "^1.4.0"
+ loader-utils "^1.4.0"
+ supports-color "^6.1.0"
+ v8-compile-cache "^2.1.1"
+ yargs "^13.3.2"
+
+webpack-sources@^1.4.0, webpack-sources@^1.4.1:
+ version "1.4.3"
+ resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
+ integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==
+ dependencies:
+ source-list-map "^2.0.0"
+ source-map "~0.6.1"
+
+webpack@^4.43.0:
+ version "4.43.0"
+ resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.43.0.tgz#c48547b11d563224c561dad1172c8aa0b8a678e6"
+ integrity sha512-GW1LjnPipFW2Y78OOab8NJlCflB7EFskMih2AHdvjbpKMeDJqEgSx24cXXXiPS65+WSwVyxtDsJH6jGX2czy+g==
+ dependencies:
+ "@webassemblyjs/ast" "1.9.0"
+ "@webassemblyjs/helper-module-context" "1.9.0"
+ "@webassemblyjs/wasm-edit" "1.9.0"
+ "@webassemblyjs/wasm-parser" "1.9.0"
+ acorn "^6.4.1"
+ ajv "^6.10.2"
+ ajv-keywords "^3.4.1"
+ chrome-trace-event "^1.0.2"
+ enhanced-resolve "^4.1.0"
+ eslint-scope "^4.0.3"
+ json-parse-better-errors "^1.0.2"
+ loader-runner "^2.4.0"
+ loader-utils "^1.2.3"
+ memory-fs "^0.4.1"
+ micromatch "^3.1.10"
+ mkdirp "^0.5.3"
+ neo-async "^2.6.1"
+ node-libs-browser "^2.2.1"
+ schema-utils "^1.0.0"
+ tapable "^1.1.3"
+ terser-webpack-plugin "^1.4.3"
+ watchpack "^1.6.1"
+ webpack-sources "^1.4.1"
+
+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@^1.2.14, which@^1.2.9, which@^1.3.1:
+ 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"
+
+worker-farm@^1.7.0:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8"
+ integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==
+ dependencies:
+ errno "~0.1.7"
+
+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"
+
+wrappy@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+ integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
+
+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@^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@^3.0.2:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
+ integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
+
+yaml@^1.7.2:
+ version "1.10.0"
+ resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.0.tgz#3b593add944876077d4d683fee01081bd9fff31e"
+ integrity sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==
+
+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@^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"